Updated interpreters
[projects/chimara/chimara.git] / interpreters / glulxe / exec.c
1 /* exec.c: Glulxe code for program execution. The main interpreter loop.
2     Designed by Andrew Plotkin <erkyrath@eblong.com>
3     http://eblong.com/zarf/glulx/index.html
4 */
5
6 #include "glk.h"
7 #include "glulxe.h"
8 #include "opcodes.h"
9
10 #ifdef FLOAT_SUPPORT
11 #include <math.h>
12 #endif /* FLOAT_SUPPORT */
13
14 /* execute_loop():
15    The main interpreter loop. This repeats until the program is done.
16 */
17 void execute_loop()
18 {
19   int done_executing = FALSE;
20   int ix;
21   glui32 opcode;
22   operandlist_t *oplist;
23   oparg_t inst[MAX_OPERANDS];
24   glui32 value, addr, val0, val1;
25   glsi32 vals0, vals1;
26   glui32 *arglist;
27   glui32 arglistfix[3];
28 #ifdef FLOAT_SUPPORT
29   gfloat32 valf, valf1, valf2;
30 #endif /* FLOAT_SUPPORT */
31
32   while (!done_executing) {
33
34     profile_tick();
35     /* Do OS-specific processing, if appropriate. */
36     glk_tick();
37
38     /* Fetch the opcode number. */
39     opcode = Mem1(pc);
40     pc++;
41     if (opcode & 0x80) {
42       /* More than one-byte opcode. */
43       if (opcode & 0x40) {
44         /* Four-byte opcode */
45         opcode &= 0x3F;
46         opcode = (opcode << 8) | Mem1(pc);
47         pc++;
48         opcode = (opcode << 8) | Mem1(pc);
49         pc++;
50         opcode = (opcode << 8) | Mem1(pc);
51         pc++;
52       }
53       else {
54         /* Two-byte opcode */
55         opcode &= 0x7F;
56         opcode = (opcode << 8) | Mem1(pc);
57         pc++;
58       }
59     }
60
61     /* Now we have an opcode number. */
62     
63     /* Fetch the structure that describes how the operands for this
64        opcode are arranged. This is a pointer to an immutable, 
65        static object. */
66     if (opcode < 0x80)
67       oplist = fast_operandlist[opcode];
68     else
69       oplist = lookup_operandlist(opcode);
70
71     if (!oplist)
72       fatal_error_i("Encountered unknown opcode.", opcode);
73
74     /* Based on the oplist structure, load the actual operand values
75        into inst. This moves the PC up to the end of the instruction. */
76     parse_operands(inst, oplist);
77
78     /* Perform the opcode. This switch statement is split in two, based
79        on some paranoid suspicions about the ability of compilers to
80        optimize large-range switches. Ignore that. */
81
82     if (opcode < 0x80) {
83
84       switch (opcode) {
85
86       case op_nop:
87         break;
88
89       case op_add:
90         value = inst[0].value + inst[1].value;
91         store_operand(inst[2].desttype, inst[2].value, value);
92         break;
93       case op_sub:
94         value = inst[0].value - inst[1].value;
95         store_operand(inst[2].desttype, inst[2].value, value);
96         break;
97       case op_mul:
98         value = inst[0].value * inst[1].value;
99         store_operand(inst[2].desttype, inst[2].value, value);
100         break;
101       case op_div:
102         vals0 = inst[0].value;
103         vals1 = inst[1].value;
104         if (vals1 == 0)
105           fatal_error("Division by zero.");
106         /* Since C doesn't guarantee the results of division of negative
107            numbers, we carefully convert everything to positive values
108            first. They have to be unsigned values, too, otherwise the
109            0x80000000 case goes wonky. */
110         if (vals0 < 0) {
111           val0 = (-vals0);
112           if (vals1 < 0) {
113             val1 = (-vals1);
114             value = val0 / val1;
115           }
116           else {
117             val1 = vals1;
118             value = -(val0 / val1);
119           }
120         }
121         else {
122           val0 = vals0;
123           if (vals1 < 0) {
124             val1 = (-vals1);
125             value = -(val0 / val1);
126           }
127           else {
128             val1 = vals1;
129             value = val0 / val1;
130           }
131         }
132         store_operand(inst[2].desttype, inst[2].value, value);
133         break;
134       case op_mod:
135         vals0 = inst[0].value;
136         vals1 = inst[1].value;
137         if (vals1 == 0)
138           fatal_error("Division by zero doing remainder.");
139         if (vals1 < 0) {
140             val1 = -vals1;
141         }
142         else {
143             val1 = vals1;
144         }
145         if (vals0 < 0) {
146           val0 = (-vals0);
147           value = -(val0 % val1);
148         }
149         else {
150           val0 = vals0;
151           value = val0 % val1;
152         }
153         store_operand(inst[2].desttype, inst[2].value, value);
154         break;
155       case op_neg:
156         vals0 = inst[0].value;
157         value = (-vals0);
158         store_operand(inst[1].desttype, inst[1].value, value);
159         break;
160
161       case op_bitand:
162         value = (inst[0].value & inst[1].value);
163         store_operand(inst[2].desttype, inst[2].value, value);
164         break;
165       case op_bitor:
166         value = (inst[0].value | inst[1].value);
167         store_operand(inst[2].desttype, inst[2].value, value);
168         break;
169       case op_bitxor:
170         value = (inst[0].value ^ inst[1].value);
171         store_operand(inst[2].desttype, inst[2].value, value);
172         break;
173       case op_bitnot:
174         value = ~(inst[0].value);
175         store_operand(inst[1].desttype, inst[1].value, value);
176         break;
177
178       case op_shiftl:
179         vals0 = inst[1].value;
180         if (vals0 < 0 || vals0 >= 32)
181           value = 0;
182         else
183           value = ((glui32)(inst[0].value) << (glui32)vals0);
184         store_operand(inst[2].desttype, inst[2].value, value);
185         break;
186       case op_ushiftr:
187         vals0 = inst[1].value;
188         if (vals0 < 0 || vals0 >= 32)
189           value = 0;
190         else
191           value = ((glui32)(inst[0].value) >> (glui32)vals0);
192         store_operand(inst[2].desttype, inst[2].value, value);
193         break;
194       case op_sshiftr:
195         vals0 = inst[1].value;
196         if (vals0 < 0 || vals0 >= 32) {
197           if (inst[0].value & 0x80000000)
198             value = 0xFFFFFFFF;
199           else
200             value = 0;
201         }
202         else {
203           /* This is somewhat foolhardy -- C doesn't guarantee that
204              right-shifting a signed value replicates the sign bit.
205              We'll assume it for now. */
206           value = ((glsi32)(inst[0].value) >> (glsi32)vals0);
207         }
208         store_operand(inst[2].desttype, inst[2].value, value);
209         break;
210
211       case op_jump:
212         value = inst[0].value;
213         /* fall through to PerformJump label. */
214
215       PerformJump: /* goto label for successful jumping... ironic, no? */
216         if (value == 0 || value == 1) {
217           /* Return from function. This is exactly what happens in
218              return_op, but it's only a few lines of code, so I won't
219              bother with a "goto". */
220           leave_function();
221           if (stackptr == 0) {
222             done_executing = TRUE;
223             break;
224           }
225           pop_callstub(value); /* zero or one */
226         }
227         else {
228           /* Branch to a new PC value. */
229           pc = (pc + value - 2);
230         }
231         break;
232
233       case op_jz:
234         if (inst[0].value == 0) {
235           value = inst[1].value;
236           goto PerformJump;
237         }
238         break;
239       case op_jnz:
240         if (inst[0].value != 0) {
241           value = inst[1].value;
242           goto PerformJump;
243         }
244         break;
245       case op_jeq:
246         if (inst[0].value == inst[1].value) {
247           value = inst[2].value;
248           goto PerformJump;
249         }
250         break;
251       case op_jne:
252         if (inst[0].value != inst[1].value) {
253           value = inst[2].value;
254           goto PerformJump;
255         }
256         break;
257       case op_jlt:
258         vals0 = inst[0].value;
259         vals1 = inst[1].value;
260         if (vals0 < vals1) {
261           value = inst[2].value;
262           goto PerformJump;
263         }
264         break;
265       case op_jgt:
266         vals0 = inst[0].value;
267         vals1 = inst[1].value;
268         if (vals0 > vals1) {
269           value = inst[2].value;
270           goto PerformJump;
271         }
272         break;
273       case op_jle:
274         vals0 = inst[0].value;
275         vals1 = inst[1].value;
276         if (vals0 <= vals1) {
277           value = inst[2].value;
278           goto PerformJump;
279         }
280         break;
281       case op_jge:
282         vals0 = inst[0].value;
283         vals1 = inst[1].value;
284         if (vals0 >= vals1) {
285           value = inst[2].value;
286           goto PerformJump;
287         }
288         break;
289       case op_jltu:
290         val0 = inst[0].value;
291         val1 = inst[1].value;
292         if (val0 < val1) {
293           value = inst[2].value;
294           goto PerformJump;
295         }
296         break;
297       case op_jgtu:
298         val0 = inst[0].value;
299         val1 = inst[1].value;
300         if (val0 > val1) {
301           value = inst[2].value;
302           goto PerformJump;
303         }
304         break;
305       case op_jleu:
306         val0 = inst[0].value;
307         val1 = inst[1].value;
308         if (val0 <= val1) {
309           value = inst[2].value;
310           goto PerformJump;
311         }
312         break;
313       case op_jgeu:
314         val0 = inst[0].value;
315         val1 = inst[1].value;
316         if (val0 >= val1) {
317           value = inst[2].value;
318           goto PerformJump;
319         }
320         break;
321
322       case op_call:
323         value = inst[1].value;
324         arglist = pop_arguments(value, 0);
325         push_callstub(inst[2].desttype, inst[2].value);
326         enter_function(inst[0].value, value, arglist);
327         break;
328       case op_return:
329         leave_function();
330         if (stackptr == 0) {
331           done_executing = TRUE;
332           break;
333         }
334         pop_callstub(inst[0].value);
335         break;
336       case op_tailcall:
337         value = inst[1].value;
338         arglist = pop_arguments(value, 0);
339         leave_function();
340         enter_function(inst[0].value, value, arglist);
341         break;
342
343       case op_catch:
344         push_callstub(inst[0].desttype, inst[0].value);
345         value = inst[1].value;
346         val0 = stackptr;
347         store_operand(inst[0].desttype, inst[0].value, val0);
348         goto PerformJump;
349         break;
350       case op_throw:
351         profile_fail("throw");
352         value = inst[0].value;
353         stackptr = inst[1].value;
354         pop_callstub(value);
355         break;
356
357       case op_copy:
358         value = inst[0].value;
359         store_operand(inst[1].desttype, inst[1].value, value);
360         break;
361       case op_copys:
362         value = inst[0].value;
363         store_operand_s(inst[1].desttype, inst[1].value, value);
364         break;
365       case op_copyb:
366         value = inst[0].value;
367         store_operand_b(inst[1].desttype, inst[1].value, value);
368         break;
369
370       case op_sexs:
371         val0 = inst[0].value;
372         if (val0 & 0x8000)
373           val0 |= 0xFFFF0000;
374         else
375           val0 &= 0x0000FFFF;
376         store_operand(inst[1].desttype, inst[1].value, val0);
377         break;
378       case op_sexb:
379         val0 = inst[0].value;
380         if (val0 & 0x80)
381           val0 |= 0xFFFFFF00;
382         else
383           val0 &= 0x000000FF;
384         store_operand(inst[1].desttype, inst[1].value, val0);
385         break;
386
387       case op_aload:
388         value = inst[0].value;
389         value += 4 * inst[1].value;
390         val0 = Mem4(value);
391         store_operand(inst[2].desttype, inst[2].value, val0);
392         break;
393       case op_aloads:
394         value = inst[0].value;
395         value += 2 * inst[1].value;
396         val0 = Mem2(value);
397         store_operand(inst[2].desttype, inst[2].value, val0);
398         break;
399       case op_aloadb:
400         value = inst[0].value;
401         value += inst[1].value;
402         val0 = Mem1(value);
403         store_operand(inst[2].desttype, inst[2].value, val0);
404         break;
405       case op_aloadbit:
406         value = inst[0].value;
407         vals0 = inst[1].value;
408         val1 = (vals0 & 7);
409         if (vals0 >= 0)
410           value += (vals0 >> 3);
411         else
412           value -= (1 + ((-1 - vals0) >> 3));
413         if (Mem1(value) & (1 << val1))
414           val0 = 1;
415         else
416           val0 = 0;
417         store_operand(inst[2].desttype, inst[2].value, val0);
418         break;
419
420       case op_astore:
421         value = inst[0].value;
422         value += 4 * inst[1].value;
423         val0 = inst[2].value;
424         MemW4(value, val0);
425         break;
426       case op_astores:
427         value = inst[0].value;
428         value += 2 * inst[1].value;
429         val0 = inst[2].value;
430         MemW2(value, val0);
431         break;
432       case op_astoreb:
433         value = inst[0].value;
434         value += inst[1].value;
435         val0 = inst[2].value;
436         MemW1(value, val0);
437         break;
438       case op_astorebit:
439         value = inst[0].value;
440         vals0 = inst[1].value;
441         val1 = (vals0 & 7);
442         if (vals0 >= 0)
443           value += (vals0 >> 3);
444         else
445           value -= (1 + ((-1 - vals0) >> 3));
446         val0 = Mem1(value);
447         if (inst[2].value)
448           val0 |= (1 << val1);
449         else
450           val0 &= ~((glui32)(1 << val1));
451         MemW1(value, val0);
452         break;
453
454       case op_stkcount:
455         value = (stackptr - valstackbase) / 4;
456         store_operand(inst[0].desttype, inst[0].value, value);
457         break;
458       case op_stkpeek:
459         vals0 = inst[0].value * 4;
460         if (vals0 < 0 || vals0 >= (stackptr - valstackbase))
461           fatal_error("Stkpeek outside current stack range.");
462         value = Stk4(stackptr - (vals0+4));
463         store_operand(inst[1].desttype, inst[1].value, value);
464         break;
465       case op_stkswap:
466         if (stackptr < valstackbase+8) {
467           fatal_error("Stack underflow in stkswap.");
468         }
469         val0 = Stk4(stackptr-4);
470         val1 = Stk4(stackptr-8);
471         StkW4(stackptr-4, val1);
472         StkW4(stackptr-8, val0);
473         break;
474       case op_stkcopy:
475         vals0 = inst[0].value;
476         if (vals0 < 0)
477           fatal_error("Negative operand in stkcopy.");
478         if (vals0 == 0)
479           break;
480         if (stackptr < valstackbase+vals0*4)
481           fatal_error("Stack underflow in stkcopy.");
482         if (stackptr + vals0*4 > stacksize) 
483           fatal_error("Stack overflow in stkcopy.");
484         addr = stackptr - vals0*4;
485         for (ix=0; ix<vals0; ix++) {
486           value = Stk4(addr + ix*4);
487           StkW4(stackptr + ix*4, value);
488         }
489         stackptr += vals0*4;
490         break;
491       case op_stkroll:
492         vals0 = inst[0].value;
493         vals1 = inst[1].value;
494         if (vals0 < 0)
495           fatal_error("Negative operand in stkroll.");
496         if (stackptr < valstackbase+vals0*4)
497           fatal_error("Stack underflow in stkroll.");
498         if (vals0 == 0)
499           break;
500         /* The following is a bit ugly. We want to do vals1 = vals0-vals1,
501            because rolling down is sort of easier than rolling up. But
502            we also want to take the result mod vals0. The % operator is
503            annoying for negative numbers, so we need to do this in two 
504            cases. */
505         if (vals1 > 0) {
506           vals1 = vals1 % vals0;
507           vals1 = (vals0) - vals1;
508         }
509         else {
510           vals1 = (-vals1) % vals0;
511         }
512         if (vals1 == 0)
513           break;
514         addr = stackptr - vals0*4;
515         for (ix=0; ix<vals1; ix++) {
516           value = Stk4(addr + ix*4);
517           StkW4(stackptr + ix*4, value);
518         }
519         for (ix=0; ix<vals0; ix++) {
520           value = Stk4(addr + (vals1+ix)*4);
521           StkW4(addr + ix*4, value);
522         }
523         break;
524
525       case op_streamchar:
526         profile_in(2, FALSE);
527         value = inst[0].value & 0xFF;
528         (*stream_char_handler)(value);
529         profile_out();
530         break;
531       case op_streamunichar:
532         profile_in(2, FALSE);
533         value = inst[0].value;
534         (*stream_unichar_handler)(value);
535         profile_out();
536         break;
537       case op_streamnum:
538         profile_in(2, FALSE);
539         vals0 = inst[0].value;
540         stream_num(vals0, FALSE, 0);
541         profile_out();
542         break;
543       case op_streamstr:
544         profile_in(2, FALSE);
545         stream_string(inst[0].value, 0, 0);
546         profile_out();
547         break;
548
549       default:
550         fatal_error_i("Executed unknown opcode.", opcode);
551       }
552     }
553     else {
554
555       switch (opcode) {
556
557       case op_gestalt:
558         value = do_gestalt(inst[0].value, inst[1].value);
559         store_operand(inst[2].desttype, inst[2].value, value);
560         break;
561
562       case op_debugtrap:
563         fatal_error_i("user debugtrap encountered.", inst[0].value);
564
565       case op_jumpabs:
566         pc = inst[0].value;
567         break;
568
569       case op_callf:
570         push_callstub(inst[1].desttype, inst[1].value);
571         enter_function(inst[0].value, 0, arglistfix);
572         break;
573       case op_callfi:
574         arglistfix[0] = inst[1].value;
575         push_callstub(inst[2].desttype, inst[2].value);
576         enter_function(inst[0].value, 1, arglistfix);
577         break;
578       case op_callfii:
579         arglistfix[0] = inst[1].value;
580         arglistfix[1] = inst[2].value;
581         push_callstub(inst[3].desttype, inst[3].value);
582         enter_function(inst[0].value, 2, arglistfix);
583         break;
584       case op_callfiii:
585         arglistfix[0] = inst[1].value;
586         arglistfix[1] = inst[2].value;
587         arglistfix[2] = inst[3].value;
588         push_callstub(inst[4].desttype, inst[4].value);
589         enter_function(inst[0].value, 3, arglistfix);
590         break;
591
592       case op_getmemsize:
593         store_operand(inst[0].desttype, inst[0].value, endmem);
594         break;
595       case op_setmemsize:
596         value = change_memsize(inst[0].value, FALSE);
597         store_operand(inst[1].desttype, inst[1].value, value);
598         break;
599
600       case op_getstringtbl:
601         value = stream_get_table();
602         store_operand(inst[0].desttype, inst[0].value, value);
603         break;
604       case op_setstringtbl:
605         stream_set_table(inst[0].value);
606         break;
607
608       case op_getiosys:
609         stream_get_iosys(&val0, &val1);
610         store_operand(inst[0].desttype, inst[0].value, val0);
611         store_operand(inst[1].desttype, inst[1].value, val1);
612         break;
613       case op_setiosys:
614         stream_set_iosys(inst[0].value, inst[1].value);
615         break;
616
617       case op_glk:
618         profile_in(1, FALSE);
619         value = inst[1].value;
620         arglist = pop_arguments(value, 0);
621         val0 = perform_glk(inst[0].value, value, arglist);
622         store_operand(inst[2].desttype, inst[2].value, val0);
623         profile_out();
624         break;
625
626       case op_random:
627         vals0 = inst[0].value;
628         if (vals0 == 0)
629           value = glulx_random();
630         else if (vals0 >= 1)
631           value = glulx_random() % (glui32)(vals0);
632         else 
633           value = -(glulx_random() % (glui32)(-vals0));
634         store_operand(inst[1].desttype, inst[1].value, value);
635         break;
636       case op_setrandom:
637         glulx_setrandom(inst[0].value);
638         break;
639
640       case op_verify:
641         value = perform_verify();
642         store_operand(inst[0].desttype, inst[0].value, value);
643         break;
644
645       case op_restart:
646         profile_fail("restart");
647         vm_restart();
648         break;
649
650       case op_protect:
651         val0 = inst[0].value;
652         val1 = val0 + inst[1].value;
653         if (val0 == val1) {
654           val0 = 0;
655           val1 = 0;
656         }
657         protectstart = val0;
658         protectend = val1;
659         break;
660
661       case op_save:
662         push_callstub(inst[1].desttype, inst[1].value);
663         value = perform_save(find_stream_by_id(inst[0].value));
664         pop_callstub(value);
665         break;
666
667       case op_restore:
668         profile_fail("restore");
669         value = perform_restore(find_stream_by_id(inst[0].value));
670         if (value == 0) {
671           /* We've succeeded, and the stack now contains the callstub
672              saved during saveundo. Ignore this opcode's operand. */
673           value = -1;
674           pop_callstub(value);
675         }
676         else {
677           /* We've failed, so we must store the failure in this opcode's
678              operand. */
679           store_operand(inst[1].desttype, inst[1].value, value);
680         }
681         break;
682
683       case op_saveundo:
684         push_callstub(inst[0].desttype, inst[0].value);
685         value = perform_saveundo();
686         pop_callstub(value);
687         break;
688
689       case op_restoreundo:
690         profile_fail("restoreundo");
691         value = perform_restoreundo();
692         if (value == 0) {
693           /* We've succeeded, and the stack now contains the callstub
694              saved during saveundo. Ignore this opcode's operand. */
695           value = -1;
696           pop_callstub(value);
697         }
698         else {
699           /* We've failed, so we must store the failure in this opcode's
700              operand. */
701           store_operand(inst[0].desttype, inst[0].value, value);
702         }
703         break;
704
705       case op_quit:
706         done_executing = TRUE;
707         break;
708
709       case op_linearsearch:
710         value = linear_search(inst[0].value, inst[1].value, inst[2].value, 
711           inst[3].value, inst[4].value, inst[5].value, inst[6].value);
712         store_operand(inst[7].desttype, inst[7].value, value);
713         break;
714       case op_binarysearch:
715         value = binary_search(inst[0].value, inst[1].value, inst[2].value, 
716           inst[3].value, inst[4].value, inst[5].value, inst[6].value);
717         store_operand(inst[7].desttype, inst[7].value, value);
718         break;
719       case op_linkedsearch:
720         value = linked_search(inst[0].value, inst[1].value, inst[2].value, 
721           inst[3].value, inst[4].value, inst[5].value);
722         store_operand(inst[6].desttype, inst[6].value, value);
723         break;
724
725       case op_mzero: {
726         glui32 lx;
727         glui32 count = inst[0].value;
728         addr = inst[1].value;
729         for (lx=0; lx<count; lx++, addr++) {
730           MemW1(addr, 0);
731         }
732         }
733         break;
734       case op_mcopy: {
735         glui32 lx;
736         glui32 count = inst[0].value;
737         glui32 addrsrc = inst[1].value;
738         glui32 addrdest = inst[2].value;
739         if (addrdest < addrsrc) {
740           for (lx=0; lx<count; lx++, addrsrc++, addrdest++) {
741             value = Mem1(addrsrc);
742             MemW1(addrdest, value);
743           }
744         }
745         else {
746           addrsrc += (count-1);
747           addrdest += (count-1);
748           for (lx=0; lx<count; lx++, addrsrc--, addrdest--) {
749             value = Mem1(addrsrc);
750             MemW1(addrdest, value);
751           }
752         }
753         }
754         break;
755       case op_malloc:
756         value = heap_alloc(inst[0].value);
757         store_operand(inst[1].desttype, inst[1].value, value);
758         break;
759       case op_mfree:
760         heap_free(inst[0].value);
761         break;
762
763       case op_accelfunc:
764         accel_set_func(inst[0].value, inst[1].value);
765         break;
766       case op_accelparam:
767         accel_set_param(inst[0].value, inst[1].value);
768         break;
769
770 #ifdef FLOAT_SUPPORT
771
772       case op_numtof:
773         vals0 = inst[0].value;
774         value = encode_float((gfloat32)vals0);
775         store_operand(inst[1].desttype, inst[1].value, value);
776         break;
777       case op_ftonumz:
778         valf = decode_float(inst[0].value);
779         if (!signbit(valf)) {
780           if (isnan(valf) || isinf(valf) || (valf > 2147483647.0))
781             vals0 = 0x7FFFFFFF;
782           else
783             vals0 = (glsi32)(truncf(valf));
784         }
785         else {
786           if (isnan(valf) || isinf(valf) || (valf < -2147483647.0))
787             vals0 = 0x80000000;
788           else
789             vals0 = (glsi32)(truncf(valf));
790         }
791         store_operand(inst[1].desttype, inst[1].value, vals0);
792         break;
793       case op_ftonumn:
794         valf = decode_float(inst[0].value);
795         if (!signbit(valf)) {
796           if (isnan(valf) || isinf(valf) || (valf > 2147483647.0))
797             vals0 = 0x7FFFFFFF;
798           else
799             vals0 = (glsi32)(roundf(valf));
800         }
801         else {
802           if (isnan(valf) || isinf(valf) || (valf < -2147483647.0))
803             vals0 = 0x80000000;
804           else
805             vals0 = (glsi32)(roundf(valf));
806         }
807         store_operand(inst[1].desttype, inst[1].value, vals0);
808         break;
809
810       case op_fadd:
811         valf1 = decode_float(inst[0].value);
812         valf2 = decode_float(inst[1].value);
813         value = encode_float(valf1 + valf2);
814         store_operand(inst[2].desttype, inst[2].value, value);
815         break;
816       case op_fsub:
817         valf1 = decode_float(inst[0].value);
818         valf2 = decode_float(inst[1].value);
819         value = encode_float(valf1 - valf2);
820         store_operand(inst[2].desttype, inst[2].value, value);
821         break;
822       case op_fmul:
823         valf1 = decode_float(inst[0].value);
824         valf2 = decode_float(inst[1].value);
825         value = encode_float(valf1 * valf2);
826         store_operand(inst[2].desttype, inst[2].value, value);
827         break;
828       case op_fdiv:
829         valf1 = decode_float(inst[0].value);
830         valf2 = decode_float(inst[1].value);
831         value = encode_float(valf1 / valf2);
832         store_operand(inst[2].desttype, inst[2].value, value);
833         break;
834
835       case op_fmod:
836         valf1 = decode_float(inst[0].value);
837         valf2 = decode_float(inst[1].value);
838         valf = fmodf(valf1, valf2);
839         val0 = encode_float(valf);
840         val1 = encode_float((valf1-valf) / valf2);
841         if (val1 == 0x0 || val1 == 0x80000000) {
842           /* When the quotient is zero, the sign has been lost in the
843              shuffle. We'll set that by hand, based on the original
844              arguments. */
845           val1 = (inst[0].value ^ inst[1].value) & 0x80000000;
846         }
847         store_operand(inst[2].desttype, inst[2].value, val0);
848         store_operand(inst[3].desttype, inst[3].value, val1);
849         break;
850
851       case op_floor:
852         valf = decode_float(inst[0].value);
853         value = encode_float(floorf(valf));
854         store_operand(inst[1].desttype, inst[1].value, value);
855         break;
856       case op_ceil:
857         valf = decode_float(inst[0].value);
858         value = encode_float(ceilf(valf));
859         if (value == 0x0 || value == 0x80000000) {
860           /* When the result is zero, the sign may have been lost in the
861              shuffle. (This is a bug in some C libraries.) We'll set the
862              sign by hand, based on the original argument. */
863           value = inst[0].value & 0x80000000;
864         }
865         store_operand(inst[1].desttype, inst[1].value, value);
866         break;
867
868       case op_sqrt:
869         valf = decode_float(inst[0].value);
870         value = encode_float(sqrtf(valf));
871         store_operand(inst[1].desttype, inst[1].value, value);
872         break;
873       case op_log:
874         valf = decode_float(inst[0].value);
875         value = encode_float(logf(valf));
876         store_operand(inst[1].desttype, inst[1].value, value);
877         break;
878       case op_exp:
879         valf = decode_float(inst[0].value);
880         value = encode_float(expf(valf));
881         store_operand(inst[1].desttype, inst[1].value, value);
882         break;
883       case op_pow:
884         valf1 = decode_float(inst[0].value);
885         valf2 = decode_float(inst[1].value);
886         value = encode_float(glulx_powf(valf1, valf2));
887         store_operand(inst[2].desttype, inst[2].value, value);
888         break;
889
890       case op_sin:
891         valf = decode_float(inst[0].value);
892         value = encode_float(sinf(valf));
893         store_operand(inst[1].desttype, inst[1].value, value);
894         break;
895       case op_cos:
896         valf = decode_float(inst[0].value);
897         value = encode_float(cosf(valf));
898         store_operand(inst[1].desttype, inst[1].value, value);
899         break;
900       case op_tan:
901         valf = decode_float(inst[0].value);
902         value = encode_float(tanf(valf));
903         store_operand(inst[1].desttype, inst[1].value, value);
904         break;
905       case op_asin:
906         valf = decode_float(inst[0].value);
907         value = encode_float(asinf(valf));
908         store_operand(inst[1].desttype, inst[1].value, value);
909         break;
910       case op_acos:
911         valf = decode_float(inst[0].value);
912         value = encode_float(acosf(valf));
913         store_operand(inst[1].desttype, inst[1].value, value);
914         break;
915       case op_atan:
916         valf = decode_float(inst[0].value);
917         value = encode_float(atanf(valf));
918         store_operand(inst[1].desttype, inst[1].value, value);
919         break;
920       case op_atan2:
921         valf1 = decode_float(inst[0].value);
922         valf2 = decode_float(inst[1].value);
923         value = encode_float(atan2f(valf1, valf2));
924         store_operand(inst[2].desttype, inst[2].value, value);
925         break;
926
927       case op_jisinf:
928         /* Infinity is well-defined, so we don't bother to convert to
929            float. */
930         val0 = inst[0].value;
931         if (val0 == 0x7F800000 || val0 == 0xFF800000) {
932           value = inst[1].value;
933           goto PerformJump;
934         }
935         break;
936       case op_jisnan:
937         /* NaN is well-defined, so we don't bother to convert to
938            float. */
939         val0 = inst[0].value;
940         if ((val0 & 0x7F800000) == 0x7F800000 && (val0 & 0x007FFFFF) != 0) {
941           value = inst[1].value;
942           goto PerformJump;
943         }
944         break;
945
946       case op_jfeq:
947         if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) {
948           /* The delta is NaN, which can never match. */
949           val0 = 0;
950         }
951         else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
952           && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
953           /* Both are infinite. Opposite infinities are never equal,
954              even if the difference is infinite, so this is easy. */
955           val0 = (inst[0].value == inst[1].value);
956         }
957         else {
958           valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
959           valf2 = fabs(decode_float(inst[2].value));
960           val0 = (valf1 <= valf2 && valf1 >= -valf2);
961         }
962         if (val0) {
963           value = inst[3].value;
964           goto PerformJump;
965         }
966         break;
967       case op_jfne:
968         if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) {
969           /* The delta is NaN, which can never match. */
970           val0 = 0;
971         }
972         else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
973           && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
974           /* Both are infinite. Opposite infinities are never equal,
975              even if the difference is infinite, so this is easy. */
976           val0 = (inst[0].value == inst[1].value);
977         }
978         else {
979           valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
980           valf2 = fabs(decode_float(inst[2].value));
981           val0 = (valf1 <= valf2 && valf1 >= -valf2);
982         }
983         if (!val0) {
984           value = inst[3].value;
985           goto PerformJump;
986         }
987         break;
988
989       case op_jflt:
990         valf1 = decode_float(inst[0].value);
991         valf2 = decode_float(inst[1].value);
992         if (valf1 < valf2) {
993           value = inst[2].value;
994           goto PerformJump;
995         }
996         break;
997       case op_jfgt:
998         valf1 = decode_float(inst[0].value);
999         valf2 = decode_float(inst[1].value);
1000         if (valf1 > valf2) {
1001           value = inst[2].value;
1002           goto PerformJump;
1003         }
1004         break;
1005       case op_jfle:
1006         valf1 = decode_float(inst[0].value);
1007         valf2 = decode_float(inst[1].value);
1008         if (valf1 <= valf2) {
1009           value = inst[2].value;
1010           goto PerformJump;
1011         }
1012         break;
1013       case op_jfge:
1014         valf1 = decode_float(inst[0].value);
1015         valf2 = decode_float(inst[1].value);
1016         if (valf1 >= valf2) {
1017           value = inst[2].value;
1018           goto PerformJump;
1019         }
1020         break;
1021
1022 #endif /* FLOAT_SUPPORT */
1023
1024       default:
1025         fatal_error_i("Executed unknown opcode.", opcode);
1026       }
1027     }
1028   }
1029 }