]> git.xonotic.org Git - xonotic/darkplaces.git/blob - prvm_execprogram.h
Better coverage output.
[xonotic/darkplaces.git] / prvm_execprogram.h
1 #ifdef PRVMTIMEPROFILING 
2 #define PreError() \
3         prog->xstatement = st - cached_statements; \
4         tm = Sys_DirtyTime(); \
5         prog->xfunction->profile += (st - startst); \
6         prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0;
7 #else
8 #define PreError() \
9         prog->xstatement = st - cached_statements; \
10         prog->xfunction->profile += (st - startst);
11 #endif
12
13 // This code isn't #ifdef/#define protectable, don't try.
14
15 #if PRVMSLOWINTERPRETER
16                 {
17                         if (prog->watch_global_type != ev_void)
18                         {
19                                 prvm_eval_t *f = PRVM_GLOBALFIELDVALUE(prog->watch_global);
20                                 prog->xstatement = st + 1 - cached_statements;
21                                 PRVM_Watchpoint(prog, 1, "Global watchpoint hit by engine", prog->watch_global_type, &prog->watch_global_value, f);
22                         }
23                         if (prog->watch_field_type != ev_void && prog->watch_edict < prog->max_edicts)
24                         {
25                                 prvm_eval_t *f = PRVM_EDICTFIELDVALUE(prog->edicts + prog->watch_edict, prog->watch_field);
26                                 prog->xstatement = st + 1 - cached_statements;
27                                 PRVM_Watchpoint(prog, 1, "Entityfield watchpoint hit by engine", prog->watch_field_type, &prog->watch_edictfield_value, f);
28                         }
29                 }
30 #endif
31
32                 while (1)
33                 {
34                         st++;
35
36 #if PRVMSLOWINTERPRETER
37                         if (prog->trace)
38                                 PRVM_PrintStatement(prog, st);
39                         if (prog->statement_profile[st - cached_statements]++ == 0 && (prvm_coverage.integer & 4))
40                                 PRVM_StatementCoverageEvent(prog, prog->xfunction, st - cached_statements);
41                         if (prog->break_statement >= 0)
42                                 if ((st - cached_statements) == prog->break_statement)
43                                 {
44                                         prog->xstatement = st - cached_statements;
45                                         PRVM_Breakpoint(prog, prog->break_stack_index, "Breakpoint hit");
46                                 }
47 #endif
48
49                         switch (st->op)
50                         {
51                         case OP_ADD_F:
52                                 OPC->_float = OPA->_float + OPB->_float;
53                                 break;
54                         case OP_ADD_V:
55                                 OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
56                                 OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
57                                 OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
58                                 break;
59                         case OP_SUB_F:
60                                 OPC->_float = OPA->_float - OPB->_float;
61                                 break;
62                         case OP_SUB_V:
63                                 OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
64                                 OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
65                                 OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
66                                 break;
67                         case OP_MUL_F:
68                                 OPC->_float = OPA->_float * OPB->_float;
69                                 break;
70                         case OP_MUL_V:
71                                 OPC->_float = OPA->vector[0]*OPB->vector[0] + OPA->vector[1]*OPB->vector[1] + OPA->vector[2]*OPB->vector[2];
72                                 break;
73                         case OP_MUL_FV:
74                                 tempfloat = OPA->_float;
75                                 OPC->vector[0] = tempfloat * OPB->vector[0];
76                                 OPC->vector[1] = tempfloat * OPB->vector[1];
77                                 OPC->vector[2] = tempfloat * OPB->vector[2];
78                                 break;
79                         case OP_MUL_VF:
80                                 tempfloat = OPB->_float;
81                                 OPC->vector[0] = tempfloat * OPA->vector[0];
82                                 OPC->vector[1] = tempfloat * OPA->vector[1];
83                                 OPC->vector[2] = tempfloat * OPA->vector[2];
84                                 break;
85                         case OP_DIV_F:
86                                 if( OPB->_float != 0.0f )
87                                 {
88                                         OPC->_float = OPA->_float / OPB->_float;
89                                 }
90                                 else
91                                 {
92                                         if (developer.integer)
93                                         {
94                                                 prog->xfunction->profile += (st - startst);
95                                                 startst = st;
96                                                 prog->xstatement = st - cached_statements;
97                                                 VM_Warning(prog, "Attempted division by zero in %s\n", prog->name );
98                                         }
99                                         OPC->_float = 0.0f;
100                                 }
101                                 break;
102                         case OP_BITAND:
103                                 OPC->_float = (prvm_int_t)OPA->_float & (prvm_int_t)OPB->_float;
104                                 break;
105                         case OP_BITOR:
106                                 OPC->_float = (prvm_int_t)OPA->_float | (prvm_int_t)OPB->_float;
107                                 break;
108                         case OP_GE:
109                                 OPC->_float = OPA->_float >= OPB->_float;
110                                 break;
111                         case OP_LE:
112                                 OPC->_float = OPA->_float <= OPB->_float;
113                                 break;
114                         case OP_GT:
115                                 OPC->_float = OPA->_float > OPB->_float;
116                                 break;
117                         case OP_LT:
118                                 OPC->_float = OPA->_float < OPB->_float;
119                                 break;
120                         case OP_AND:
121                                 OPC->_float = FLOAT_IS_TRUE_FOR_INT(OPA->_int) && FLOAT_IS_TRUE_FOR_INT(OPB->_int); // TODO change this back to float, and add AND_I to be used by fteqcc for anything not a float
122                                 break;
123                         case OP_OR:
124                                 OPC->_float = FLOAT_IS_TRUE_FOR_INT(OPA->_int) || FLOAT_IS_TRUE_FOR_INT(OPB->_int); // TODO change this back to float, and add OR_I to be used by fteqcc for anything not a float
125                                 break;
126                         case OP_NOT_F:
127                                 OPC->_float = !FLOAT_IS_TRUE_FOR_INT(OPA->_int);
128                                 break;
129                         case OP_NOT_V:
130                                 OPC->_float = !OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2];
131                                 break;
132                         case OP_NOT_S:
133                                 OPC->_float = !OPA->string || !*PRVM_GetString(prog, OPA->string);
134                                 break;
135                         case OP_NOT_FNC:
136                                 OPC->_float = !OPA->function;
137                                 break;
138                         case OP_NOT_ENT:
139                                 OPC->_float = (OPA->edict == 0);
140                                 break;
141                         case OP_EQ_F:
142                                 OPC->_float = OPA->_float == OPB->_float;
143                                 break;
144                         case OP_EQ_V:
145                                 OPC->_float = (OPA->vector[0] == OPB->vector[0]) && (OPA->vector[1] == OPB->vector[1]) && (OPA->vector[2] == OPB->vector[2]);
146                                 break;
147                         case OP_EQ_S:
148                                 OPC->_float = !strcmp(PRVM_GetString(prog, OPA->string),PRVM_GetString(prog, OPB->string));
149                                 break;
150                         case OP_EQ_E:
151                                 OPC->_float = OPA->_int == OPB->_int;
152                                 break;
153                         case OP_EQ_FNC:
154                                 OPC->_float = OPA->function == OPB->function;
155                                 break;
156                         case OP_NE_F:
157                                 OPC->_float = OPA->_float != OPB->_float;
158                                 break;
159                         case OP_NE_V:
160                                 OPC->_float = (OPA->vector[0] != OPB->vector[0]) || (OPA->vector[1] != OPB->vector[1]) || (OPA->vector[2] != OPB->vector[2]);
161                                 break;
162                         case OP_NE_S:
163                                 OPC->_float = strcmp(PRVM_GetString(prog, OPA->string),PRVM_GetString(prog, OPB->string));
164                                 break;
165                         case OP_NE_E:
166                                 OPC->_float = OPA->_int != OPB->_int;
167                                 break;
168                         case OP_NE_FNC:
169                                 OPC->_float = OPA->function != OPB->function;
170                                 break;
171
172                 //==================
173                         case OP_STORE_F:
174                         case OP_STORE_ENT:
175                         case OP_STORE_FLD:              // integers
176                         case OP_STORE_S:
177                         case OP_STORE_FNC:              // pointers
178                                 OPB->_int = OPA->_int;
179                                 break;
180                         case OP_STORE_V:
181                                 OPB->ivector[0] = OPA->ivector[0];
182                                 OPB->ivector[1] = OPA->ivector[1];
183                                 OPB->ivector[2] = OPA->ivector[2];
184                                 break;
185
186                         case OP_STOREP_F:
187                         case OP_STOREP_ENT:
188                         case OP_STOREP_FLD:             // integers
189                         case OP_STOREP_S:
190                         case OP_STOREP_FNC:             // pointers
191                                 if ((prvm_uint_t)OPB->_int - cached_entityfields >= cached_entityfieldsarea_entityfields)
192                                 {
193                                         if ((prvm_uint_t)OPB->_int >= cached_entityfieldsarea)
194                                         {
195                                                 PreError();
196                                                 prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int);
197                                                 goto cleanup;
198                                         }
199                                         if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites)
200                                         {
201                                                 prog->xstatement = st - cached_statements;
202                                                 VM_Warning(prog, "assignment to world.%s (field %i) in %s\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int, prog->name);
203                                         }
204                                 }
205                                 ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int);
206                                 ptr->_int = OPA->_int;
207                                 break;
208                         case OP_STOREP_V:
209                                 if ((prvm_uint_t)OPB->_int - cached_entityfields > (prvm_uint_t)cached_entityfieldsarea_entityfields_3)
210                                 {
211                                         if ((prvm_uint_t)OPB->_int > cached_entityfieldsarea_3)
212                                         {
213                                                 PreError();
214                                                 prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int);
215                                                 goto cleanup;
216                                         }
217                                         if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites)
218                                         {
219                                                 prog->xstatement = st - cached_statements;
220                                                 VM_Warning(prog, "assignment to world.%s (field %i) in %s\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int, prog->name);
221                                         }
222                                 }
223                                 ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int);
224                                 ptr->ivector[0] = OPA->ivector[0];
225                                 ptr->ivector[1] = OPA->ivector[1];
226                                 ptr->ivector[2] = OPA->ivector[2];
227                                 break;
228
229                         case OP_ADDRESS:
230                                 if ((prvm_uint_t)OPA->edict >= cached_max_edicts)
231                                 {
232                                         PreError();
233                                         prog->error_cmd("%s Progs attempted to address an out of bounds edict number", prog->name);
234                                         goto cleanup;
235                                 }
236                                 if ((prvm_uint_t)OPB->_int >= cached_entityfields)
237                                 {
238                                         PreError();
239                                         prog->error_cmd("%s attempted to address an invalid field (%i) in an edict", prog->name, (int)OPB->_int);
240                                         goto cleanup;
241                                 }
242 #if 0
243                                 if (OPA->edict == 0 && !cached_allowworldwrites)
244                                 {
245                                         PreError();
246                                         prog->error_cmd("forbidden assignment to null/world entity in %s", prog->name);
247                                         goto cleanup;
248                                 }
249 #endif
250                                 OPC->_int = OPA->edict * cached_entityfields + OPB->_int;
251                                 break;
252
253                         case OP_LOAD_F:
254                         case OP_LOAD_FLD:
255                         case OP_LOAD_ENT:
256                         case OP_LOAD_S:
257                         case OP_LOAD_FNC:
258                                 if ((prvm_uint_t)OPA->edict >= cached_max_edicts)
259                                 {
260                                         PreError();
261                                         prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name);
262                                         goto cleanup;
263                                 }
264                                 if ((prvm_uint_t)OPB->_int >= cached_entityfields)
265                                 {
266                                         PreError();
267                                         prog->error_cmd("%s attempted to read an invalid field in an edict (%i)", prog->name, (int)OPB->_int);
268                                         goto cleanup;
269                                 }
270                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
271                                 OPC->_int = ((prvm_eval_t *)(ed->fields.ip + OPB->_int))->_int;
272                                 break;
273
274                         case OP_LOAD_V:
275                                 if ((prvm_uint_t)OPA->edict >= cached_max_edicts)
276                                 {
277                                         PreError();
278                                         prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name);
279                                         goto cleanup;
280                                 }
281                                 if ((prvm_uint_t)OPB->_int > cached_entityfields_3)
282                                 {
283                                         PreError();
284                                         prog->error_cmd("%s attempted to read an invalid field in an edict (%i)", prog->name, (int)OPB->_int);
285                                         goto cleanup;
286                                 }
287                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
288                                 ptr = (prvm_eval_t *)(ed->fields.ip + OPB->_int);
289                                 OPC->ivector[0] = ptr->ivector[0];
290                                 OPC->ivector[1] = ptr->ivector[1];
291                                 OPC->ivector[2] = ptr->ivector[2];
292                                 break;
293
294                 //==================
295
296                         case OP_IFNOT:
297                                 if(!FLOAT_IS_TRUE_FOR_INT(OPA->_int))
298                                 // TODO add an "int-if", and change this one to OPA->_float
299                                 // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero)
300                                 // and entity, string, field values can never have that value
301                                 {
302                                         prog->xfunction->profile += (st - startst);
303                                         st = cached_statements + st->jumpabsolute - 1;  // offset the st++
304                                         startst = st;
305                                         // no bounds check needed, it is done when loading progs
306                                         if (++jumpcount == 10000000 && prvm_runawaycheck)
307                                         {
308                                                 prog->xstatement = st - cached_statements;
309                                                 PRVM_Profile(prog, 1<<30, 1000000, 0);
310                                                 prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount);
311                                         }
312                                 }
313                                 break;
314
315                         case OP_IF:
316                                 if(FLOAT_IS_TRUE_FOR_INT(OPA->_int))
317                                 // TODO add an "int-if", and change this one, as well as the FLOAT_IS_TRUE_FOR_INT usages, to OPA->_float
318                                 // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero)
319                                 // and entity, string, field values can never have that value
320                                 {
321                                         prog->xfunction->profile += (st - startst);
322                                         st = cached_statements + st->jumpabsolute - 1;  // offset the st++
323                                         startst = st;
324                                         // no bounds check needed, it is done when loading progs
325                                         if (++jumpcount == 10000000 && prvm_runawaycheck)
326                                         {
327                                                 prog->xstatement = st - cached_statements;
328                                                 PRVM_Profile(prog, 1<<30, 0.01, 0);
329                                                 prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount);
330                                         }
331                                 }
332                                 break;
333
334                         case OP_GOTO:
335                                 prog->xfunction->profile += (st - startst);
336                                 st = cached_statements + st->jumpabsolute - 1;  // offset the st++
337                                 startst = st;
338                                 // no bounds check needed, it is done when loading progs
339                                 if (++jumpcount == 10000000 && prvm_runawaycheck)
340                                 {
341                                         prog->xstatement = st - cached_statements;
342                                         PRVM_Profile(prog, 1<<30, 0.01, 0);
343                                         prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount);
344                                 }
345                                 break;
346
347                         case OP_CALL0:
348                         case OP_CALL1:
349                         case OP_CALL2:
350                         case OP_CALL3:
351                         case OP_CALL4:
352                         case OP_CALL5:
353                         case OP_CALL6:
354                         case OP_CALL7:
355                         case OP_CALL8:
356 #ifdef PRVMTIMEPROFILING 
357                                 tm = Sys_DirtyTime();
358                                 prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0;
359                                 starttm = tm;
360 #endif
361                                 prog->xfunction->profile += (st - startst);
362                                 startst = st;
363                                 prog->xstatement = st - cached_statements;
364                                 prog->argc = st->op - OP_CALL0;
365                                 if (!OPA->function)
366                                         prog->error_cmd("NULL function in %s", prog->name);
367
368                                 if(!OPA->function || OPA->function < 0 || OPA->function >= prog->numfunctions)
369                                 {
370                                         PreError();
371                                         prog->error_cmd("%s CALL outside the program", prog->name);
372                                         goto cleanup;
373                                 }
374
375                                 newf = &prog->functions[OPA->function];
376                                 if (newf->callcount++ == 0 && (prvm_coverage.integer & 1))
377                                         PRVM_FunctionCoverageEvent(prog, newf);
378
379                                 if (newf->first_statement < 0)
380                                 {
381                                         // negative first_statement values are built in functions
382                                         int builtinnumber = -newf->first_statement;
383                                         prog->xfunction->builtinsprofile++;
384                                         if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
385                                         {
386                                                 prog->builtins[builtinnumber](prog);
387 #ifdef PRVMTIMEPROFILING 
388                                                 tm = Sys_DirtyTime();
389                                                 newf->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0;
390                                                 prog->xfunction->tbprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0;
391                                                 starttm = tm;
392 #endif
393                                                 // builtins may cause ED_Alloc() to be called, update cached variables
394                                                 cached_edictsfields = prog->edictsfields;
395                                                 cached_entityfields = prog->entityfields;
396                                                 cached_entityfields_3 = prog->entityfields - 3;
397                                                 cached_entityfieldsarea = prog->entityfieldsarea;
398                                                 cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
399                                                 cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
400                                                 cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
401                                                 cached_max_edicts = prog->max_edicts;
402                                                 // these do not change
403                                                 //cached_statements = prog->statements;
404                                                 //cached_allowworldwrites = prog->allowworldwrites;
405                                                 //cached_flag = prog->flag;
406                                                 // if prog->trace changed we need to change interpreter path
407                                                 if (prog->trace != cachedpr_trace)
408                                                         goto chooseexecprogram;
409                                         }
410                                         else
411                                                 prog->error_cmd("No such builtin #%i in %s; most likely cause: outdated engine build. Try updating!", builtinnumber, prog->name);
412                                 }
413                                 else
414                                         st = cached_statements + PRVM_EnterFunction(prog, newf);
415                                 startst = st;
416                                 break;
417
418                         case OP_DONE:
419                         case OP_RETURN:
420 #ifdef PRVMTIMEPROFILING 
421                                 tm = Sys_DirtyTime();
422                                 prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0;
423                                 starttm = tm;
424 #endif
425                                 prog->xfunction->profile += (st - startst);
426                                 prog->xstatement = st - cached_statements;
427
428                                 prog->globals.ip[OFS_RETURN  ] = prog->globals.ip[st->operand[0]  ];
429                                 prog->globals.ip[OFS_RETURN+1] = prog->globals.ip[st->operand[0]+1];
430                                 prog->globals.ip[OFS_RETURN+2] = prog->globals.ip[st->operand[0]+2];
431
432                                 st = cached_statements + PRVM_LeaveFunction(prog);
433                                 startst = st;
434                                 if (prog->depth <= exitdepth)
435                                         goto cleanup; // all done
436                                 break;
437
438                         case OP_STATE:
439                                 if(cached_flag & PRVM_OP_STATE)
440                                 {
441                                         ed = PRVM_PROG_TO_EDICT(PRVM_gameglobaledict(self));
442                                         PRVM_gameedictfloat(ed,nextthink) = PRVM_gameglobalfloat(time) + 0.1;
443                                         PRVM_gameedictfloat(ed,frame) = OPA->_float;
444                                         PRVM_gameedictfunction(ed,think) = OPB->function;
445                                 }
446                                 else
447                                 {
448                                         PreError();
449                                         prog->xstatement = st - cached_statements;
450                                         prog->error_cmd("OP_STATE not supported by %s", prog->name);
451                                 }
452                                 break;
453
454 // LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized
455 /*
456                         case OP_ADD_I:
457                                 OPC->_int = OPA->_int + OPB->_int;
458                                 break;
459                         case OP_ADD_IF:
460                                 OPC->_int = OPA->_int + (prvm_int_t) OPB->_float;
461                                 break;
462                         case OP_ADD_FI:
463                                 OPC->_float = OPA->_float + (prvm_vec_t) OPB->_int;
464                                 break;
465                         case OP_SUB_I:
466                                 OPC->_int = OPA->_int - OPB->_int;
467                                 break;
468                         case OP_SUB_IF:
469                                 OPC->_int = OPA->_int - (prvm_int_t) OPB->_float;
470                                 break;
471                         case OP_SUB_FI:
472                                 OPC->_float = OPA->_float - (prvm_vec_t) OPB->_int;
473                                 break;
474                         case OP_MUL_I:
475                                 OPC->_int = OPA->_int * OPB->_int;
476                                 break;
477                         case OP_MUL_IF:
478                                 OPC->_int = OPA->_int * (prvm_int_t) OPB->_float;
479                                 break;
480                         case OP_MUL_FI:
481                                 OPC->_float = OPA->_float * (prvm_vec_t) OPB->_int;
482                                 break;
483                         case OP_MUL_VI:
484                                 OPC->vector[0] = (prvm_vec_t) OPB->_int * OPA->vector[0];
485                                 OPC->vector[1] = (prvm_vec_t) OPB->_int * OPA->vector[1];
486                                 OPC->vector[2] = (prvm_vec_t) OPB->_int * OPA->vector[2];
487                                 break;
488                         case OP_DIV_VF:
489                                 {
490                                         float temp = 1.0f / OPB->_float;
491                                         OPC->vector[0] = temp * OPA->vector[0];
492                                         OPC->vector[1] = temp * OPA->vector[1];
493                                         OPC->vector[2] = temp * OPA->vector[2];
494                                 }
495                                 break;
496                         case OP_DIV_I:
497                                 OPC->_int = OPA->_int / OPB->_int;
498                                 break;
499                         case OP_DIV_IF:
500                                 OPC->_int = OPA->_int / (prvm_int_t) OPB->_float;
501                                 break;
502                         case OP_DIV_FI:
503                                 OPC->_float = OPA->_float / (prvm_vec_t) OPB->_int;
504                                 break;
505                         case OP_CONV_IF:
506                                 OPC->_float = OPA->_int;
507                                 break;
508                         case OP_CONV_FI:
509                                 OPC->_int = OPA->_float;
510                                 break;
511                         case OP_BITAND_I:
512                                 OPC->_int = OPA->_int & OPB->_int;
513                                 break;
514                         case OP_BITOR_I:
515                                 OPC->_int = OPA->_int | OPB->_int;
516                                 break;
517                         case OP_BITAND_IF:
518                                 OPC->_int = OPA->_int & (prvm_int_t)OPB->_float;
519                                 break;
520                         case OP_BITOR_IF:
521                                 OPC->_int = OPA->_int | (prvm_int_t)OPB->_float;
522                                 break;
523                         case OP_BITAND_FI:
524                                 OPC->_float = (prvm_int_t)OPA->_float & OPB->_int;
525                                 break;
526                         case OP_BITOR_FI:
527                                 OPC->_float = (prvm_int_t)OPA->_float | OPB->_int;
528                                 break;
529                         case OP_GE_I:
530                                 OPC->_float = OPA->_int >= OPB->_int;
531                                 break;
532                         case OP_LE_I:
533                                 OPC->_float = OPA->_int <= OPB->_int;
534                                 break;
535                         case OP_GT_I:
536                                 OPC->_float = OPA->_int > OPB->_int;
537                                 break;
538                         case OP_LT_I:
539                                 OPC->_float = OPA->_int < OPB->_int;
540                                 break;
541                         case OP_AND_I:
542                                 OPC->_float = OPA->_int && OPB->_int;
543                                 break;
544                         case OP_OR_I:
545                                 OPC->_float = OPA->_int || OPB->_int;
546                                 break;
547                         case OP_GE_IF:
548                                 OPC->_float = (prvm_vec_t)OPA->_int >= OPB->_float;
549                                 break;
550                         case OP_LE_IF:
551                                 OPC->_float = (prvm_vec_t)OPA->_int <= OPB->_float;
552                                 break;
553                         case OP_GT_IF:
554                                 OPC->_float = (prvm_vec_t)OPA->_int > OPB->_float;
555                                 break;
556                         case OP_LT_IF:
557                                 OPC->_float = (prvm_vec_t)OPA->_int < OPB->_float;
558                                 break;
559                         case OP_AND_IF:
560                                 OPC->_float = (prvm_vec_t)OPA->_int && OPB->_float;
561                                 break;
562                         case OP_OR_IF:
563                                 OPC->_float = (prvm_vec_t)OPA->_int || OPB->_float;
564                                 break;
565                         case OP_GE_FI:
566                                 OPC->_float = OPA->_float >= (prvm_vec_t)OPB->_int;
567                                 break;
568                         case OP_LE_FI:
569                                 OPC->_float = OPA->_float <= (prvm_vec_t)OPB->_int;
570                                 break;
571                         case OP_GT_FI:
572                                 OPC->_float = OPA->_float > (prvm_vec_t)OPB->_int;
573                                 break;
574                         case OP_LT_FI:
575                                 OPC->_float = OPA->_float < (prvm_vec_t)OPB->_int;
576                                 break;
577                         case OP_AND_FI:
578                                 OPC->_float = OPA->_float && (prvm_vec_t)OPB->_int;
579                                 break;
580                         case OP_OR_FI:
581                                 OPC->_float = OPA->_float || (prvm_vec_t)OPB->_int;
582                                 break;
583                         case OP_NOT_I:
584                                 OPC->_float = !OPA->_int;
585                                 break;
586                         case OP_EQ_I:
587                                 OPC->_float = OPA->_int == OPB->_int;
588                                 break;
589                         case OP_EQ_IF:
590                                 OPC->_float = (prvm_vec_t)OPA->_int == OPB->_float;
591                                 break;
592                         case OP_EQ_FI:
593                                 OPC->_float = OPA->_float == (prvm_vec_t)OPB->_int;
594                                 break;
595                         case OP_NE_I:
596                                 OPC->_float = OPA->_int != OPB->_int;
597                                 break;
598                         case OP_NE_IF:
599                                 OPC->_float = (prvm_vec_t)OPA->_int != OPB->_float;
600                                 break;
601                         case OP_NE_FI:
602                                 OPC->_float = OPA->_float != (prvm_vec_t)OPB->_int;
603                                 break;
604                         case OP_STORE_I:
605                                 OPB->_int = OPA->_int;
606                                 break;
607                         case OP_STOREP_I:
608 #if PRBOUNDSCHECK
609                                 if (OPB->_int < 0 || OPB->_int + 4 > pr_edictareasize)
610                                 {
611                                         PreError();
612                                         prog->error_cmd("%s Progs attempted to write to an out of bounds edict", prog->name);
613                                         goto cleanup;
614                                 }
615 #endif
616                                 ptr = (prvm_eval_t *)(prog->edictsfields + OPB->_int);
617                                 ptr->_int = OPA->_int;
618                                 break;
619                         case OP_LOAD_I:
620 #if PRBOUNDSCHECK
621                                 if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
622                                 {
623                                         PreError();
624                                         prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name);
625                                         goto cleanup;
626                                 }
627                                 if (OPB->_int < 0 || OPB->_int >= progs->entityfields)
628                                 {
629                                         PreError();
630                                         prog->error_cmd("%s Progs attempted to read an invalid field in an edict", prog->name);
631                                         goto cleanup;
632                                 }
633 #endif
634                                 ed = PRVM_PROG_TO_EDICT(OPA->edict);
635                                 OPC->_int = ((prvm_eval_t *)((int *)ed->v + OPB->_int))->_int;
636                                 break;
637
638                         case OP_GSTOREP_I:
639                         case OP_GSTOREP_F:
640                         case OP_GSTOREP_ENT:
641                         case OP_GSTOREP_FLD:            // integers
642                         case OP_GSTOREP_S:
643                         case OP_GSTOREP_FNC:            // pointers
644 #if PRBOUNDSCHECK
645                                 if (OPB->_int < 0 || OPB->_int >= pr_globaldefs)
646                                 {
647                                         PreError();
648                                         prog->error_cmd("%s Progs attempted to write to an invalid indexed global", prog->name);
649                                         goto cleanup;
650                                 }
651 #endif
652                                 pr_iglobals[OPB->_int] = OPA->_int;
653                                 break;
654                         case OP_GSTOREP_V:
655 #if PRBOUNDSCHECK
656                                 if (OPB->_int < 0 || OPB->_int + 2 >= pr_globaldefs)
657                                 {
658                                         PreError();
659                                         prog->error_cmd("%s Progs attempted to write to an invalid indexed global", prog->name);
660                                         goto cleanup;
661                                 }
662 #endif
663                                 pr_iglobals[OPB->_int  ] = OPA->ivector[0];
664                                 pr_iglobals[OPB->_int+1] = OPA->ivector[1];
665                                 pr_iglobals[OPB->_int+2] = OPA->ivector[2];
666                                 break;
667
668                         case OP_GADDRESS:
669                                 i = OPA->_int + (prvm_int_t) OPB->_float;
670 #if PRBOUNDSCHECK
671                                 if (i < 0 || i >= pr_globaldefs)
672                                 {
673                                         PreError();
674                                         prog->error_cmd("%s Progs attempted to address an out of bounds global", prog->name);
675                                         goto cleanup;
676                                 }
677 #endif
678                                 OPC->_int = pr_iglobals[i];
679                                 break;
680
681                         case OP_GLOAD_I:
682                         case OP_GLOAD_F:
683                         case OP_GLOAD_FLD:
684                         case OP_GLOAD_ENT:
685                         case OP_GLOAD_S:
686                         case OP_GLOAD_FNC:
687 #if PRBOUNDSCHECK
688                                 if (OPA->_int < 0 || OPA->_int >= pr_globaldefs)
689                                 {
690                                         PreError();
691                                         prog->error_cmd("%s Progs attempted to read an invalid indexed global", prog->name);
692                                         goto cleanup;
693                                 }
694 #endif
695                                 OPC->_int = pr_iglobals[OPA->_int];
696                                 break;
697
698                         case OP_GLOAD_V:
699 #if PRBOUNDSCHECK
700                                 if (OPA->_int < 0 || OPA->_int + 2 >= pr_globaldefs)
701                                 {
702                                         PreError();
703                                         prog->error_cmd("%s Progs attempted to read an invalid indexed global", prog->name);
704                                         goto cleanup;
705                                 }
706 #endif
707                                 OPC->ivector[0] = pr_iglobals[OPA->_int  ];
708                                 OPC->ivector[1] = pr_iglobals[OPA->_int+1];
709                                 OPC->ivector[2] = pr_iglobals[OPA->_int+2];
710                                 break;
711
712                         case OP_BOUNDCHECK:
713                                 if (OPA->_int < 0 || OPA->_int >= st->b)
714                                 {
715                                         PreError();
716                                         prog->error_cmd("%s Progs boundcheck failed at line number %d, value is < 0 or >= %d", prog->name, st->b, st->c);
717                                         goto cleanup;
718                                 }
719                                 break;
720
721 */
722
723                         default:
724                                 PreError();
725                                 prog->error_cmd("Bad opcode %i in %s", st->op, prog->name);
726                                 goto cleanup;
727                         }
728 #if PRVMSLOWINTERPRETER
729                         {
730                                 if (prog->watch_global_type != ev_void)
731                                 {
732                                         prvm_eval_t *f = PRVM_GLOBALFIELDVALUE(prog->watch_global);
733                                         prog->xstatement = st - cached_statements;
734                                         PRVM_Watchpoint(prog, 0, "Global watchpoint hit", prog->watch_global_type, &prog->watch_global_value, f);
735                                 }
736                                 if (prog->watch_field_type != ev_void && prog->watch_edict < prog->max_edicts)
737                                 {
738                                         prvm_eval_t *f = PRVM_EDICTFIELDVALUE(prog->edicts + prog->watch_edict, prog->watch_field);
739                                         prog->xstatement = st - cached_statements;
740                                         PRVM_Watchpoint(prog, 0, "Entityfield watchpoint hit", prog->watch_field_type, &prog->watch_edictfield_value, f);
741                                 }
742                         }
743 #endif
744                 }
745
746 #undef PreError