X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=interpreters%2Fglulxe%2Fexec.c;fp=interpreters%2Fglulxe%2Fexec.c;h=4dd3fcdc757d7c36f9e5159b11088bbe766f13c6;hb=75009f8f40bbb580194e1722db76f4644bf18641;hp=03ac456aff88d11a36ee522c3cd299c03dfc522e;hpb=89081782541e85e079f64839ffb26b4e74273eb7;p=projects%2Fchimara%2Fchimara.git diff --git a/interpreters/glulxe/exec.c b/interpreters/glulxe/exec.c index 03ac456..4dd3fcd 100644 --- a/interpreters/glulxe/exec.c +++ b/interpreters/glulxe/exec.c @@ -7,6 +7,10 @@ #include "glulxe.h" #include "opcodes.h" +#ifdef FLOAT_SUPPORT +#include +#endif /* FLOAT_SUPPORT */ + /* execute_loop(): The main interpreter loop. This repeats until the program is done. */ @@ -16,11 +20,14 @@ void execute_loop() int ix; glui32 opcode; operandlist_t *oplist; - instruction_t inst; + oparg_t inst[MAX_OPERANDS]; glui32 value, addr, val0, val1; glsi32 vals0, vals1; glui32 *arglist; glui32 arglistfix[3]; +#ifdef FLOAT_SUPPORT + gfloat32 valf, valf1, valf2; +#endif /* FLOAT_SUPPORT */ while (!done_executing) { @@ -66,7 +73,7 @@ void execute_loop() /* Based on the oplist structure, load the actual operand values into inst. This moves the PC up to the end of the instruction. */ - parse_operands(&inst, oplist); + parse_operands(inst, oplist); /* Perform the opcode. This switch statement is split in two, based on some paranoid suspicions about the ability of compilers to @@ -80,96 +87,114 @@ void execute_loop() break; case op_add: - value = inst.value[0] + inst.value[1]; - store_operand(inst.desttype, inst.value[2], value); + value = inst[0].value + inst[1].value; + store_operand(inst[2].desttype, inst[2].value, value); break; case op_sub: - value = inst.value[0] - inst.value[1]; - store_operand(inst.desttype, inst.value[2], value); + value = inst[0].value - inst[1].value; + store_operand(inst[2].desttype, inst[2].value, value); break; case op_mul: - value = inst.value[0] * inst.value[1]; - store_operand(inst.desttype, inst.value[2], value); + value = inst[0].value * inst[1].value; + store_operand(inst[2].desttype, inst[2].value, value); break; case op_div: - vals0 = inst.value[0]; - vals1 = inst.value[1]; + vals0 = inst[0].value; + vals1 = inst[1].value; if (vals1 == 0) fatal_error("Division by zero."); /* Since C doesn't guarantee the results of division of negative numbers, we carefully convert everything to positive values - first. */ - if (vals1 < 0) { - vals0 = (-vals0); - vals1 = (-vals1); - } - if (vals0 >= 0) { - value = vals0 / vals1; + first. They have to be unsigned values, too, otherwise the + 0x80000000 case goes wonky. */ + if (vals0 < 0) { + val0 = (-vals0); + if (vals1 < 0) { + val1 = (-vals1); + value = val0 / val1; + } + else { + val1 = vals1; + value = -(val0 / val1); + } } else { - value = -((-vals0) / vals1); + val0 = vals0; + if (vals1 < 0) { + val1 = (-vals1); + value = -(val0 / val1); + } + else { + val1 = vals1; + value = val0 / val1; + } } - store_operand(inst.desttype, inst.value[2], value); + store_operand(inst[2].desttype, inst[2].value, value); break; case op_mod: - vals0 = inst.value[0]; - vals1 = inst.value[1]; + vals0 = inst[0].value; + vals1 = inst[1].value; if (vals1 == 0) fatal_error("Division by zero doing remainder."); if (vals1 < 0) { - vals1 = (-vals1); + val1 = -vals1; } - if (vals0 >= 0) { - value = vals0 % vals1; + else { + val1 = vals1; + } + if (vals0 < 0) { + val0 = (-vals0); + value = -(val0 % val1); } else { - value = -((-vals0) % vals1); + val0 = vals0; + value = val0 % val1; } - store_operand(inst.desttype, inst.value[2], value); + store_operand(inst[2].desttype, inst[2].value, value); break; case op_neg: - vals0 = inst.value[0]; + vals0 = inst[0].value; value = (-vals0); - store_operand(inst.desttype, inst.value[1], value); + store_operand(inst[1].desttype, inst[1].value, value); break; case op_bitand: - value = (inst.value[0] & inst.value[1]); - store_operand(inst.desttype, inst.value[2], value); + value = (inst[0].value & inst[1].value); + store_operand(inst[2].desttype, inst[2].value, value); break; case op_bitor: - value = (inst.value[0] | inst.value[1]); - store_operand(inst.desttype, inst.value[2], value); + value = (inst[0].value | inst[1].value); + store_operand(inst[2].desttype, inst[2].value, value); break; case op_bitxor: - value = (inst.value[0] ^ inst.value[1]); - store_operand(inst.desttype, inst.value[2], value); + value = (inst[0].value ^ inst[1].value); + store_operand(inst[2].desttype, inst[2].value, value); break; case op_bitnot: - value = ~(inst.value[0]); - store_operand(inst.desttype, inst.value[1], value); + value = ~(inst[0].value); + store_operand(inst[1].desttype, inst[1].value, value); break; case op_shiftl: - vals0 = inst.value[1]; + vals0 = inst[1].value; if (vals0 < 0 || vals0 >= 32) value = 0; else - value = ((glui32)(inst.value[0]) << (glui32)vals0); - store_operand(inst.desttype, inst.value[2], value); + value = ((glui32)(inst[0].value) << (glui32)vals0); + store_operand(inst[2].desttype, inst[2].value, value); break; case op_ushiftr: - vals0 = inst.value[1]; + vals0 = inst[1].value; if (vals0 < 0 || vals0 >= 32) value = 0; else - value = ((glui32)(inst.value[0]) >> (glui32)vals0); - store_operand(inst.desttype, inst.value[2], value); + value = ((glui32)(inst[0].value) >> (glui32)vals0); + store_operand(inst[2].desttype, inst[2].value, value); break; case op_sshiftr: - vals0 = inst.value[1]; + vals0 = inst[1].value; if (vals0 < 0 || vals0 >= 32) { - if (inst.value[0] & 0x80000000) + if (inst[0].value & 0x80000000) value = 0xFFFFFFFF; else value = 0; @@ -178,13 +203,13 @@ void execute_loop() /* This is somewhat foolhardy -- C doesn't guarantee that right-shifting a signed value replicates the sign bit. We'll assume it for now. */ - value = ((glsi32)(inst.value[0]) >> (glsi32)vals0); + value = ((glsi32)(inst[0].value) >> (glsi32)vals0); } - store_operand(inst.desttype, inst.value[2], value); + store_operand(inst[2].desttype, inst[2].value, value); break; case op_jump: - value = inst.value[0]; + value = inst[0].value; /* fall through to PerformJump label. */ PerformJump: /* goto label for successful jumping... ironic, no? */ @@ -206,99 +231,99 @@ void execute_loop() break; case op_jz: - if (inst.value[0] == 0) { - value = inst.value[1]; + if (inst[0].value == 0) { + value = inst[1].value; goto PerformJump; } break; case op_jnz: - if (inst.value[0] != 0) { - value = inst.value[1]; + if (inst[0].value != 0) { + value = inst[1].value; goto PerformJump; } break; case op_jeq: - if (inst.value[0] == inst.value[1]) { - value = inst.value[2]; + if (inst[0].value == inst[1].value) { + value = inst[2].value; goto PerformJump; } break; case op_jne: - if (inst.value[0] != inst.value[1]) { - value = inst.value[2]; + if (inst[0].value != inst[1].value) { + value = inst[2].value; goto PerformJump; } break; case op_jlt: - vals0 = inst.value[0]; - vals1 = inst.value[1]; + vals0 = inst[0].value; + vals1 = inst[1].value; if (vals0 < vals1) { - value = inst.value[2]; + value = inst[2].value; goto PerformJump; } break; case op_jgt: - vals0 = inst.value[0]; - vals1 = inst.value[1]; + vals0 = inst[0].value; + vals1 = inst[1].value; if (vals0 > vals1) { - value = inst.value[2]; + value = inst[2].value; goto PerformJump; } break; case op_jle: - vals0 = inst.value[0]; - vals1 = inst.value[1]; + vals0 = inst[0].value; + vals1 = inst[1].value; if (vals0 <= vals1) { - value = inst.value[2]; + value = inst[2].value; goto PerformJump; } break; case op_jge: - vals0 = inst.value[0]; - vals1 = inst.value[1]; + vals0 = inst[0].value; + vals1 = inst[1].value; if (vals0 >= vals1) { - value = inst.value[2]; + value = inst[2].value; goto PerformJump; } break; case op_jltu: - val0 = inst.value[0]; - val1 = inst.value[1]; + val0 = inst[0].value; + val1 = inst[1].value; if (val0 < val1) { - value = inst.value[2]; + value = inst[2].value; goto PerformJump; } break; case op_jgtu: - val0 = inst.value[0]; - val1 = inst.value[1]; + val0 = inst[0].value; + val1 = inst[1].value; if (val0 > val1) { - value = inst.value[2]; + value = inst[2].value; goto PerformJump; } break; case op_jleu: - val0 = inst.value[0]; - val1 = inst.value[1]; + val0 = inst[0].value; + val1 = inst[1].value; if (val0 <= val1) { - value = inst.value[2]; + value = inst[2].value; goto PerformJump; } break; case op_jgeu: - val0 = inst.value[0]; - val1 = inst.value[1]; + val0 = inst[0].value; + val1 = inst[1].value; if (val0 >= val1) { - value = inst.value[2]; + value = inst[2].value; goto PerformJump; } break; case op_call: - value = inst.value[1]; + value = inst[1].value; arglist = pop_arguments(value, 0); - push_callstub(inst.desttype, inst.value[2]); - enter_function(inst.value[0], value, arglist); + push_callstub(inst[2].desttype, inst[2].value); + enter_function(inst[0].value, value, arglist); break; case op_return: leave_function(); @@ -306,120 +331,120 @@ void execute_loop() done_executing = TRUE; break; } - pop_callstub(inst.value[0]); + pop_callstub(inst[0].value); break; case op_tailcall: - value = inst.value[1]; + value = inst[1].value; arglist = pop_arguments(value, 0); leave_function(); - enter_function(inst.value[0], value, arglist); + enter_function(inst[0].value, value, arglist); break; case op_catch: - push_callstub(inst.desttype, inst.value[0]); - value = inst.value[1]; + push_callstub(inst[0].desttype, inst[0].value); + value = inst[1].value; val0 = stackptr; - store_operand(inst.desttype, inst.value[0], val0); + store_operand(inst[0].desttype, inst[0].value, val0); goto PerformJump; break; case op_throw: profile_fail("throw"); - value = inst.value[0]; - stackptr = inst.value[1]; + value = inst[0].value; + stackptr = inst[1].value; pop_callstub(value); break; case op_copy: - value = inst.value[0]; - store_operand(inst.desttype, inst.value[1], value); + value = inst[0].value; + store_operand(inst[1].desttype, inst[1].value, value); break; case op_copys: - value = inst.value[0]; - store_operand_s(inst.desttype, inst.value[1], value); + value = inst[0].value; + store_operand_s(inst[1].desttype, inst[1].value, value); break; case op_copyb: - value = inst.value[0]; - store_operand_b(inst.desttype, inst.value[1], value); + value = inst[0].value; + store_operand_b(inst[1].desttype, inst[1].value, value); break; case op_sexs: - val0 = inst.value[0]; + val0 = inst[0].value; if (val0 & 0x8000) val0 |= 0xFFFF0000; else val0 &= 0x0000FFFF; - store_operand(inst.desttype, inst.value[1], val0); + store_operand(inst[1].desttype, inst[1].value, val0); break; case op_sexb: - val0 = inst.value[0]; + val0 = inst[0].value; if (val0 & 0x80) val0 |= 0xFFFFFF00; else val0 &= 0x000000FF; - store_operand(inst.desttype, inst.value[1], val0); + store_operand(inst[1].desttype, inst[1].value, val0); break; case op_aload: - value = inst.value[0]; - value += 4 * inst.value[1]; + value = inst[0].value; + value += 4 * inst[1].value; val0 = Mem4(value); - store_operand(inst.desttype, inst.value[2], val0); + store_operand(inst[2].desttype, inst[2].value, val0); break; case op_aloads: - value = inst.value[0]; - value += 2 * inst.value[1]; + value = inst[0].value; + value += 2 * inst[1].value; val0 = Mem2(value); - store_operand(inst.desttype, inst.value[2], val0); + store_operand(inst[2].desttype, inst[2].value, val0); break; case op_aloadb: - value = inst.value[0]; - value += inst.value[1]; + value = inst[0].value; + value += inst[1].value; val0 = Mem1(value); - store_operand(inst.desttype, inst.value[2], val0); + store_operand(inst[2].desttype, inst[2].value, val0); break; case op_aloadbit: - value = inst.value[0]; - vals0 = inst.value[1]; + value = inst[0].value; + vals0 = inst[1].value; val1 = (vals0 & 7); if (vals0 >= 0) value += (vals0 >> 3); else - value -= ((-1 - vals0) >> 3); + value -= (1 + ((-1 - vals0) >> 3)); if (Mem1(value) & (1 << val1)) val0 = 1; else val0 = 0; - store_operand(inst.desttype, inst.value[2], val0); + store_operand(inst[2].desttype, inst[2].value, val0); break; case op_astore: - value = inst.value[0]; - value += 4 * inst.value[1]; - val0 = inst.value[2]; + value = inst[0].value; + value += 4 * inst[1].value; + val0 = inst[2].value; MemW4(value, val0); break; case op_astores: - value = inst.value[0]; - value += 2 * inst.value[1]; - val0 = inst.value[2]; + value = inst[0].value; + value += 2 * inst[1].value; + val0 = inst[2].value; MemW2(value, val0); break; case op_astoreb: - value = inst.value[0]; - value += inst.value[1]; - val0 = inst.value[2]; + value = inst[0].value; + value += inst[1].value; + val0 = inst[2].value; MemW1(value, val0); break; case op_astorebit: - value = inst.value[0]; - vals0 = inst.value[1]; + value = inst[0].value; + vals0 = inst[1].value; val1 = (vals0 & 7); if (vals0 >= 0) value += (vals0 >> 3); else - value -= ((-1 - vals0) >> 3); + value -= (1 + ((-1 - vals0) >> 3)); val0 = Mem1(value); - if (inst.value[2]) + if (inst[2].value) val0 |= (1 << val1); else val0 &= ~((glui32)(1 << val1)); @@ -428,14 +453,14 @@ void execute_loop() case op_stkcount: value = (stackptr - valstackbase) / 4; - store_operand(inst.desttype, inst.value[0], value); + store_operand(inst[0].desttype, inst[0].value, value); break; case op_stkpeek: - vals0 = inst.value[0] * 4; + vals0 = inst[0].value * 4; if (vals0 < 0 || vals0 >= (stackptr - valstackbase)) fatal_error("Stkpeek outside current stack range."); value = Stk4(stackptr - (vals0+4)); - store_operand(inst.desttype, inst.value[1], value); + store_operand(inst[1].desttype, inst[1].value, value); break; case op_stkswap: if (stackptr < valstackbase+8) { @@ -447,7 +472,7 @@ void execute_loop() StkW4(stackptr-8, val0); break; case op_stkcopy: - vals0 = inst.value[0]; + vals0 = inst[0].value; if (vals0 < 0) fatal_error("Negative operand in stkcopy."); if (vals0 == 0) @@ -464,8 +489,8 @@ void execute_loop() stackptr += vals0*4; break; case op_stkroll: - vals0 = inst.value[0]; - vals1 = inst.value[1]; + vals0 = inst[0].value; + vals1 = inst[1].value; if (vals0 < 0) fatal_error("Negative operand in stkroll."); if (stackptr < valstackbase+vals0*4) @@ -499,25 +524,25 @@ void execute_loop() case op_streamchar: profile_in(2, FALSE); - value = inst.value[0] & 0xFF; + value = inst[0].value & 0xFF; (*stream_char_handler)(value); profile_out(); break; case op_streamunichar: profile_in(2, FALSE); - value = inst.value[0]; + value = inst[0].value; (*stream_unichar_handler)(value); profile_out(); break; case op_streamnum: profile_in(2, FALSE); - vals0 = inst.value[0]; + vals0 = inst[0].value; stream_num(vals0, FALSE, 0); profile_out(); break; case op_streamstr: profile_in(2, FALSE); - stream_string(inst.value[0], 0, 0); + stream_string(inst[0].value, 0, 0); profile_out(); break; @@ -530,91 +555,91 @@ void execute_loop() switch (opcode) { case op_gestalt: - value = do_gestalt(inst.value[0], inst.value[1]); - store_operand(inst.desttype, inst.value[2], value); + value = do_gestalt(inst[0].value, inst[1].value); + store_operand(inst[2].desttype, inst[2].value, value); break; case op_debugtrap: - fatal_error_i("user debugtrap encountered.", inst.value[0]); + fatal_error_i("user debugtrap encountered.", inst[0].value); case op_jumpabs: - pc = inst.value[0]; + pc = inst[0].value; break; case op_callf: - push_callstub(inst.desttype, inst.value[1]); - enter_function(inst.value[0], 0, arglistfix); + push_callstub(inst[1].desttype, inst[1].value); + enter_function(inst[0].value, 0, arglistfix); break; case op_callfi: - arglistfix[0] = inst.value[1]; - push_callstub(inst.desttype, inst.value[2]); - enter_function(inst.value[0], 1, arglistfix); + arglistfix[0] = inst[1].value; + push_callstub(inst[2].desttype, inst[2].value); + enter_function(inst[0].value, 1, arglistfix); break; case op_callfii: - arglistfix[0] = inst.value[1]; - arglistfix[1] = inst.value[2]; - push_callstub(inst.desttype, inst.value[3]); - enter_function(inst.value[0], 2, arglistfix); + arglistfix[0] = inst[1].value; + arglistfix[1] = inst[2].value; + push_callstub(inst[3].desttype, inst[3].value); + enter_function(inst[0].value, 2, arglistfix); break; case op_callfiii: - arglistfix[0] = inst.value[1]; - arglistfix[1] = inst.value[2]; - arglistfix[2] = inst.value[3]; - push_callstub(inst.desttype, inst.value[4]); - enter_function(inst.value[0], 3, arglistfix); + arglistfix[0] = inst[1].value; + arglistfix[1] = inst[2].value; + arglistfix[2] = inst[3].value; + push_callstub(inst[4].desttype, inst[4].value); + enter_function(inst[0].value, 3, arglistfix); break; case op_getmemsize: - store_operand(inst.desttype, inst.value[0], endmem); + store_operand(inst[0].desttype, inst[0].value, endmem); break; case op_setmemsize: - value = change_memsize(inst.value[0], FALSE); - store_operand(inst.desttype, inst.value[1], value); + value = change_memsize(inst[0].value, FALSE); + store_operand(inst[1].desttype, inst[1].value, value); break; case op_getstringtbl: value = stream_get_table(); - store_operand(inst.desttype, inst.value[0], value); + store_operand(inst[0].desttype, inst[0].value, value); break; case op_setstringtbl: - stream_set_table(inst.value[0]); + stream_set_table(inst[0].value); break; case op_getiosys: stream_get_iosys(&val0, &val1); - store_operand(inst.desttype, inst.value[0], val0); - store_operand(inst.desttype, inst.value[1], val1); + store_operand(inst[0].desttype, inst[0].value, val0); + store_operand(inst[1].desttype, inst[1].value, val1); break; case op_setiosys: - stream_set_iosys(inst.value[0], inst.value[1]); + stream_set_iosys(inst[0].value, inst[1].value); break; case op_glk: profile_in(1, FALSE); - value = inst.value[1]; + value = inst[1].value; arglist = pop_arguments(value, 0); - val0 = perform_glk(inst.value[0], value, arglist); - store_operand(inst.desttype, inst.value[2], val0); + val0 = perform_glk(inst[0].value, value, arglist); + store_operand(inst[2].desttype, inst[2].value, val0); profile_out(); break; case op_random: - vals0 = inst.value[0]; + vals0 = inst[0].value; if (vals0 == 0) - value = glulx_random() ^ (glulx_random() << 16); + value = glulx_random(); else if (vals0 >= 1) value = glulx_random() % (glui32)(vals0); else value = -(glulx_random() % (glui32)(-vals0)); - store_operand(inst.desttype, inst.value[1], value); + store_operand(inst[1].desttype, inst[1].value, value); break; case op_setrandom: - glulx_setrandom(inst.value[0]); + glulx_setrandom(inst[0].value); break; case op_verify: value = perform_verify(); - store_operand(inst.desttype, inst.value[0], value); + store_operand(inst[0].desttype, inst[0].value, value); break; case op_restart: @@ -623,8 +648,8 @@ void execute_loop() break; case op_protect: - val0 = inst.value[0]; - val1 = val0 + inst.value[1]; + val0 = inst[0].value; + val1 = val0 + inst[1].value; if (val0 == val1) { val0 = 0; val1 = 0; @@ -634,14 +659,14 @@ void execute_loop() break; case op_save: - push_callstub(inst.desttype, inst.value[1]); - value = perform_save(find_stream_by_id(inst.value[0])); + push_callstub(inst[1].desttype, inst[1].value); + value = perform_save(find_stream_by_id(inst[0].value)); pop_callstub(value); break; case op_restore: profile_fail("restore"); - value = perform_restore(find_stream_by_id(inst.value[0])); + value = perform_restore(find_stream_by_id(inst[0].value)); if (value == 0) { /* We've succeeded, and the stack now contains the callstub saved during saveundo. Ignore this opcode's operand. */ @@ -651,12 +676,12 @@ void execute_loop() else { /* We've failed, so we must store the failure in this opcode's operand. */ - store_operand(inst.desttype, inst.value[1], value); + store_operand(inst[1].desttype, inst[1].value, value); } break; case op_saveundo: - push_callstub(inst.desttype, inst.value[0]); + push_callstub(inst[0].desttype, inst[0].value); value = perform_saveundo(); pop_callstub(value); break; @@ -673,7 +698,7 @@ void execute_loop() else { /* We've failed, so we must store the failure in this opcode's operand. */ - store_operand(inst.desttype, inst.value[0], value); + store_operand(inst[0].desttype, inst[0].value, value); } break; @@ -682,25 +707,25 @@ void execute_loop() break; case op_linearsearch: - value = linear_search(inst.value[0], inst.value[1], inst.value[2], - inst.value[3], inst.value[4], inst.value[5], inst.value[6]); - store_operand(inst.desttype, inst.value[7], value); + value = linear_search(inst[0].value, inst[1].value, inst[2].value, + inst[3].value, inst[4].value, inst[5].value, inst[6].value); + store_operand(inst[7].desttype, inst[7].value, value); break; case op_binarysearch: - value = binary_search(inst.value[0], inst.value[1], inst.value[2], - inst.value[3], inst.value[4], inst.value[5], inst.value[6]); - store_operand(inst.desttype, inst.value[7], value); + value = binary_search(inst[0].value, inst[1].value, inst[2].value, + inst[3].value, inst[4].value, inst[5].value, inst[6].value); + store_operand(inst[7].desttype, inst[7].value, value); break; case op_linkedsearch: - value = linked_search(inst.value[0], inst.value[1], inst.value[2], - inst.value[3], inst.value[4], inst.value[5]); - store_operand(inst.desttype, inst.value[6], value); + value = linked_search(inst[0].value, inst[1].value, inst[2].value, + inst[3].value, inst[4].value, inst[5].value); + store_operand(inst[6].desttype, inst[6].value, value); break; case op_mzero: { glui32 lx; - glui32 count = inst.value[0]; - addr = inst.value[1]; + glui32 count = inst[0].value; + addr = inst[1].value; for (lx=0; lx 2147483647.0)) + vals0 = 0x7FFFFFFF; + else + vals0 = (glsi32)(truncf(valf)); + } + else { + if (isnan(valf) || isinf(valf) || (valf < -2147483647.0)) + vals0 = 0x80000000; + else + vals0 = (glsi32)(truncf(valf)); + } + store_operand(inst[1].desttype, inst[1].value, vals0); + break; + case op_ftonumn: + valf = decode_float(inst[0].value); + if (!signbit(valf)) { + if (isnan(valf) || isinf(valf) || (valf > 2147483647.0)) + vals0 = 0x7FFFFFFF; + else + vals0 = (glsi32)(roundf(valf)); + } + else { + if (isnan(valf) || isinf(valf) || (valf < -2147483647.0)) + vals0 = 0x80000000; + else + vals0 = (glsi32)(roundf(valf)); + } + store_operand(inst[1].desttype, inst[1].value, vals0); + break; + + case op_fadd: + valf1 = decode_float(inst[0].value); + valf2 = decode_float(inst[1].value); + value = encode_float(valf1 + valf2); + store_operand(inst[2].desttype, inst[2].value, value); + break; + case op_fsub: + valf1 = decode_float(inst[0].value); + valf2 = decode_float(inst[1].value); + value = encode_float(valf1 - valf2); + store_operand(inst[2].desttype, inst[2].value, value); + break; + case op_fmul: + valf1 = decode_float(inst[0].value); + valf2 = decode_float(inst[1].value); + value = encode_float(valf1 * valf2); + store_operand(inst[2].desttype, inst[2].value, value); + break; + case op_fdiv: + valf1 = decode_float(inst[0].value); + valf2 = decode_float(inst[1].value); + value = encode_float(valf1 / valf2); + store_operand(inst[2].desttype, inst[2].value, value); + break; + + case op_fmod: + valf1 = decode_float(inst[0].value); + valf2 = decode_float(inst[1].value); + valf = fmodf(valf1, valf2); + val0 = encode_float(valf); + val1 = encode_float((valf1-valf) / valf2); + if (val1 == 0x0 || val1 == 0x80000000) { + /* When the quotient is zero, the sign has been lost in the + shuffle. We'll set that by hand, based on the original + arguments. */ + val1 = (inst[0].value ^ inst[1].value) & 0x80000000; + } + store_operand(inst[2].desttype, inst[2].value, val0); + store_operand(inst[3].desttype, inst[3].value, val1); + break; + + case op_floor: + valf = decode_float(inst[0].value); + value = encode_float(floorf(valf)); + store_operand(inst[1].desttype, inst[1].value, value); + break; + case op_ceil: + valf = decode_float(inst[0].value); + value = encode_float(ceilf(valf)); + if (value == 0x0 || value == 0x80000000) { + /* When the result is zero, the sign may have been lost in the + shuffle. (This is a bug in some C libraries.) We'll set the + sign by hand, based on the original argument. */ + value = inst[0].value & 0x80000000; + } + store_operand(inst[1].desttype, inst[1].value, value); + break; + + case op_sqrt: + valf = decode_float(inst[0].value); + value = encode_float(sqrtf(valf)); + store_operand(inst[1].desttype, inst[1].value, value); + break; + case op_log: + valf = decode_float(inst[0].value); + value = encode_float(logf(valf)); + store_operand(inst[1].desttype, inst[1].value, value); + break; + case op_exp: + valf = decode_float(inst[0].value); + value = encode_float(expf(valf)); + store_operand(inst[1].desttype, inst[1].value, value); + break; + case op_pow: + valf1 = decode_float(inst[0].value); + valf2 = decode_float(inst[1].value); + value = encode_float(glulx_powf(valf1, valf2)); + store_operand(inst[2].desttype, inst[2].value, value); + break; + + case op_sin: + valf = decode_float(inst[0].value); + value = encode_float(sinf(valf)); + store_operand(inst[1].desttype, inst[1].value, value); + break; + case op_cos: + valf = decode_float(inst[0].value); + value = encode_float(cosf(valf)); + store_operand(inst[1].desttype, inst[1].value, value); + break; + case op_tan: + valf = decode_float(inst[0].value); + value = encode_float(tanf(valf)); + store_operand(inst[1].desttype, inst[1].value, value); + break; + case op_asin: + valf = decode_float(inst[0].value); + value = encode_float(asinf(valf)); + store_operand(inst[1].desttype, inst[1].value, value); + break; + case op_acos: + valf = decode_float(inst[0].value); + value = encode_float(acosf(valf)); + store_operand(inst[1].desttype, inst[1].value, value); + break; + case op_atan: + valf = decode_float(inst[0].value); + value = encode_float(atanf(valf)); + store_operand(inst[1].desttype, inst[1].value, value); + break; + case op_atan2: + valf1 = decode_float(inst[0].value); + valf2 = decode_float(inst[1].value); + value = encode_float(atan2f(valf1, valf2)); + store_operand(inst[2].desttype, inst[2].value, value); + break; + + case op_jisinf: + /* Infinity is well-defined, so we don't bother to convert to + float. */ + val0 = inst[0].value; + if (val0 == 0x7F800000 || val0 == 0xFF800000) { + value = inst[1].value; + goto PerformJump; + } + break; + case op_jisnan: + /* NaN is well-defined, so we don't bother to convert to + float. */ + val0 = inst[0].value; + if ((val0 & 0x7F800000) == 0x7F800000 && (val0 & 0x007FFFFF) != 0) { + value = inst[1].value; + goto PerformJump; + } + break; + + case op_jfeq: + if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) { + /* The delta is NaN, which can never match. */ + val0 = 0; + } + else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000) + && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) { + /* Both are infinite. Opposite infinities are never equal, + even if the difference is infinite, so this is easy. */ + val0 = (inst[0].value == inst[1].value); + } + else { + valf1 = decode_float(inst[1].value) - decode_float(inst[0].value); + valf2 = fabs(decode_float(inst[2].value)); + val0 = (valf1 <= valf2 && valf1 >= -valf2); + } + if (val0) { + value = inst[3].value; + goto PerformJump; + } + break; + case op_jfne: + if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) { + /* The delta is NaN, which can never match. */ + val0 = 0; + } + else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000) + && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) { + /* Both are infinite. Opposite infinities are never equal, + even if the difference is infinite, so this is easy. */ + val0 = (inst[0].value == inst[1].value); + } + else { + valf1 = decode_float(inst[1].value) - decode_float(inst[0].value); + valf2 = fabs(decode_float(inst[2].value)); + val0 = (valf1 <= valf2 && valf1 >= -valf2); + } + if (!val0) { + value = inst[3].value; + goto PerformJump; + } + break; + + case op_jflt: + valf1 = decode_float(inst[0].value); + valf2 = decode_float(inst[1].value); + if (valf1 < valf2) { + value = inst[2].value; + goto PerformJump; + } + break; + case op_jfgt: + valf1 = decode_float(inst[0].value); + valf2 = decode_float(inst[1].value); + if (valf1 > valf2) { + value = inst[2].value; + goto PerformJump; + } + break; + case op_jfle: + valf1 = decode_float(inst[0].value); + valf2 = decode_float(inst[1].value); + if (valf1 <= valf2) { + value = inst[2].value; + goto PerformJump; + } + break; + case op_jfge: + valf1 = decode_float(inst[0].value); + valf2 = decode_float(inst[1].value); + if (valf1 >= valf2) { + value = inst[2].value; + goto PerformJump; + } + break; + +#endif /* FLOAT_SUPPORT */ + default: fatal_error_i("Executed unknown opcode.", opcode); }