diff --git a/source/m3_compile.c b/source/m3_compile.c index 25da91c..937663a 100644 --- a/source/m3_compile.c +++ b/source/m3_compile.c @@ -859,7 +859,7 @@ M3Result GetBlockScope (IM3Compilation o, IM3CompilationScope * o_scope, i32 i //------------------------------------------------------------------------------------------------------------------------- -M3Result Compile_Const_i32 (IM3Compilation o, u8 i_opcode) +M3Result Compile_Const_i32 (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -871,7 +871,7 @@ _ (PushConst (o, value, c_m3Type_i32)); m3log (compile, } -M3Result Compile_Const_i64 (IM3Compilation o, u8 i_opcode) +M3Result Compile_Const_i64 (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -883,7 +883,7 @@ _ (PushConst (o, value, c_m3Type_i64)); m3log (compile, } -M3Result Compile_Const_f32 (IM3Compilation o, u8 i_opcode) +M3Result Compile_Const_f32 (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -896,7 +896,7 @@ _ (PushConst (o, value.u, c_m3Type_f32)); } -M3Result Compile_Const_f64 (IM3Compilation o, u8 i_opcode) +M3Result Compile_Const_f64 (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -908,8 +908,36 @@ _ (PushConst (o, value.u, c_m3Type_f64)); _catch: return result; } +#ifdef d_m3CompileExtendedOpcode -M3Result Compile_Return (IM3Compilation o, u8 i_opcode) +M3Result Compile_ExtendedOpcode (IM3Compilation o, m3opcode_t i_opcode) +{ + M3Result result; + + i32 value; + + u8 opcode; +_ (Read_u8 (& opcode, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (FC: %" PRIi32 ")", get_indention_string (o), opcode); + + i_opcode = (i_opcode << 8) | opcode; + + //printf("Extended opcode: 0x%x\n", i_opcode); + + M3Compiler compiler = GetOpInfo(i_opcode)->compiler; + + if (compiler) + result = (* compiler) (o, i_opcode); + else + result = m3Err_noCompiler; + + o->previousOpcode = i_opcode; + + _catch: return result; +} + +#endif + +M3Result Compile_Return (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -929,7 +957,7 @@ _ (EmitOp (o, op_Return)); } -M3Result Compile_End (IM3Compilation o, u8 i_opcode) +M3Result Compile_End (IM3Compilation o, m3opcode_t i_opcode) { M3Result result = m3Err_none; @@ -972,7 +1000,7 @@ _ (EmitOp (o, op_Return)); -M3Result Compile_SetLocal (IM3Compilation o, u8 i_opcode) +M3Result Compile_SetLocal (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1000,7 +1028,7 @@ _ (Pop (o)); } -M3Result Compile_GetLocal (IM3Compilation o, u8 i_opcode) +M3Result Compile_GetLocal (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1065,7 +1093,7 @@ _ (Pop (o)); } -M3Result Compile_GetSetGlobal (IM3Compilation o, u8 i_opcode) +M3Result Compile_GetSetGlobal (IM3Compilation o, m3opcode_t i_opcode) { M3Result result = m3Err_none; @@ -1088,7 +1116,7 @@ _ (ReadLEB_u32 (& globalIndex, & o->wasm, o->wasmEnd)); } -M3Result Compile_Branch (IM3Compilation o, u8 i_opcode) +M3Result Compile_Branch (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1181,7 +1209,7 @@ _ (AcquirePatch (o, & patch)); -M3Result Compile_BranchTable (IM3Compilation o, u8 i_opcode) +M3Result Compile_BranchTable (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1312,7 +1340,7 @@ _ (Push (o, i_type->returnType, topSlot)); } -M3Result Compile_Call (IM3Compilation o, u8 i_opcode) +M3Result Compile_Call (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1361,7 +1389,7 @@ _ (EmitOp (o, op)); } -M3Result Compile_CallIndirect (IM3Compilation o, u8 i_opcode) +M3Result Compile_CallIndirect (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1392,7 +1420,7 @@ _ (EmitOp (o, op_CallIndirect)); } -M3Result Compile_Memory_Current (IM3Compilation o, u8 i_opcode) +M3Result Compile_Memory_Current (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1407,7 +1435,7 @@ _ (PushRegister (o, c_m3Type_i32)); } -M3Result Compile_Memory_Grow (IM3Compilation o, u8 i_opcode) +M3Result Compile_Memory_Grow (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1472,7 +1500,7 @@ _ (FindReferencedLocalWithinCurrentBlock (o, & preservedSlotIndex, i)) } -M3Result Compile_LoopOrBlock (IM3Compilation o, u8 i_opcode) +M3Result Compile_LoopOrBlock (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1518,7 +1546,7 @@ _ (EmitOp (o, op_Branch)); } -M3Result Compile_If (IM3Compilation o, u8 i_opcode) +M3Result Compile_If (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1555,7 +1583,7 @@ _ (CompileElseBlock (o, pc, blockType)); } -M3Result Compile_Select (IM3Compilation o, u8 i_opcode) +M3Result Compile_Select (IM3Compilation o, m3opcode_t i_opcode) { static const IM3Operation intSelectOps [2] [4] = { { op_Select_i32_rss, op_Select_i32_srs, op_Select_i32_ssr, op_Select_i32_sss }, { op_Select_i64_rss, op_Select_i64_srs, op_Select_i64_ssr, op_Select_i64_sss } }; @@ -1638,20 +1666,20 @@ _ (PushRegister (o, type)); } -M3Result Compile_Drop (IM3Compilation o, u8 i_opcode) +M3Result Compile_Drop (IM3Compilation o, m3opcode_t i_opcode) { M3Result result = Pop (o); m3logif (stack, dump_type_stack (o)) return result; } -M3Result Compile_Nop (IM3Compilation o, u8 i_opcode) +M3Result Compile_Nop (IM3Compilation o, m3opcode_t i_opcode) { return m3Err_none; } -M3Result Compile_Unreachable (IM3Compilation o, u8 i_opcode) +M3Result Compile_Unreachable (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1667,11 +1695,11 @@ _ (EmitOp (o, op_Unreachable)); // TODO OPTZ: currently all stack slot indicies take up a full word, but // dual stack source operands could be packed together -M3Result Compile_Operator (IM3Compilation o, u8 i_opcode) +M3Result Compile_Operator (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; - const M3OpInfo * op = & c_operations [i_opcode]; + const M3OpInfo * op = GetOpInfo(i_opcode); IM3Operation operation; @@ -1748,11 +1776,11 @@ _ (PushRegister (o, op->type)); } -M3Result Compile_Convert (IM3Compilation o, u8 i_opcode) +M3Result Compile_Convert (IM3Compilation o, m3opcode_t i_opcode) { M3Result result = m3Err_none; - const M3OpInfo * opInfo = & c_operations [i_opcode]; + const M3OpInfo * opInfo = GetOpInfo(i_opcode); bool destInSlot = IsRegisterTypeAllocated (o, opInfo->type); bool sourceInSlot = IsStackTopInSlot (o); @@ -1771,7 +1799,7 @@ _ (PushRegister (o, opInfo->type)) } -M3Result Compile_Load_Store (IM3Compilation o, u8 i_opcode) +M3Result Compile_Load_Store (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -1781,7 +1809,7 @@ _try { _ (ReadLEB_u32 (& alignHint, & o->wasm, o->wasmEnd)); _ (ReadLEB_u32 (& memoryOffset, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (offset = %d)", get_indention_string (o), memoryOffset); - const M3OpInfo * op = & c_operations [i_opcode]; + const M3OpInfo * op = GetOpInfo(i_opcode); if (IsFpType (op->type)) _ (PreserveRegisterIfOccupied (o, c_m3Type_f64)); @@ -2056,12 +2084,32 @@ const M3OpInfo c_operations [] = d_m3DebugTypedOp (SetGlobal), d_m3DebugOp (SetGlobal_s32), d_m3DebugOp (SetGlobal_s64), d_m3DebugTypedOp (SetRegister), d_m3DebugTypedOp (SetSlot), d_m3DebugTypedOp (PreserveSetSlot), +# endif - M3OP( "termination for find_operation_info ()", 0, c_m3Type_void ) +# ifdef d_m3CompileExtendedOpcode + [0xFC] = M3OP( "0xFC", 0, c_m3Type_void, d_emptyOpList, Compile_ExtendedOpcode ), +# endif +# ifdef DEBUG + M3OP( "termination", 0, c_m3Type_void ) // for find_operation_info # endif }; +const M3OpInfo c_operationsFC [] = +{ + M3OP( "i32.trunc_s:sat/f32",0, i_32, d_convertOpList (i32_TruncSat_f32), Compile_Convert ), // 0x00 + M3OP( "i32.trunc_u:sat/f32",0, i_32, d_convertOpList (u32_TruncSat_f32), Compile_Convert ), // 0x01 + M3OP( "i32.trunc_s:sat/f64",0, i_32, d_convertOpList (i32_TruncSat_f64), Compile_Convert ), // 0x02 + M3OP( "i32.trunc_u:sat/f64",0, i_32, d_convertOpList (u32_TruncSat_f64), Compile_Convert ), // 0x03 + M3OP( "i64.trunc_s:sat/f32",0, i_64, d_convertOpList (i64_TruncSat_f32), Compile_Convert ), // 0x04 + M3OP( "i64.trunc_u:sat/f32",0, i_64, d_convertOpList (u64_TruncSat_f32), Compile_Convert ), // 0x05 + M3OP( "i64.trunc_s:sat/f64",0, i_64, d_convertOpList (i64_TruncSat_f64), Compile_Convert ), // 0x06 + M3OP( "i64.trunc_u:sat/f64",0, i_64, d_convertOpList (u64_TruncSat_f64), Compile_Convert ), // 0x07 + +# ifdef DEBUG + M3OP( "termination", 0, c_m3Type_void ) // for find_operation_info +# endif +}; M3Result Compile_BlockStatements (IM3Compilation o) { @@ -2069,10 +2117,15 @@ M3Result Compile_BlockStatements (IM3Compilation o) while (o->wasm < o->wasmEnd) { emit_stack_dump (o); - u8 opcode = * (o->wasm++); log_opcode (o, opcode); - const M3OpInfo * op = & c_operations [opcode]; + m3opcode_t opcode = * (o->wasm++); log_opcode (o, opcode); + +#ifndef d_m3CompileExtendedOpcode + if (UNLIKELY(opcode == 0xFC)) { + opcode = (opcode << 8) | (* (o->wasm++)); + } +#endif - M3Compiler compiler = op->compiler; + M3Compiler compiler = GetOpInfo(opcode)->compiler; if (not compiler) compiler = Compile_Operator; diff --git a/source/m3_compile.h b/source/m3_compile.h index 60678d7..76f5573 100644 --- a/source/m3_compile.h +++ b/source/m3_compile.h @@ -54,7 +54,7 @@ typedef struct M3CompilationScope // i32 loopDepth; i16 initStackIndex; u8 type; - u8 opcode; + m3opcode_t opcode; bool isPolymorphic; } M3CompilationScope; @@ -105,13 +105,13 @@ typedef struct u16 regStackIndexPlusOne [2]; - u8 previousOpcode; + m3opcode_t previousOpcode; } M3Compilation; typedef M3Compilation * IM3Compilation; -typedef M3Result (* M3Compiler) (IM3Compilation, u8); +typedef M3Result (* M3Compiler) (IM3Compilation, m3opcode_t); //----------------------------------------------------------------------------------------------------------------------------------- @@ -137,6 +137,16 @@ M3OpInfo; typedef const M3OpInfo * IM3OpInfo; extern const M3OpInfo c_operations []; +extern const M3OpInfo c_operationsFC []; + +static inline +const M3OpInfo* GetOpInfo(m3opcode_t opcode) { + switch (opcode >> 8) { + case 0x00: return &c_operations[opcode]; + case 0xFC: return &c_operationsFC[opcode & 0xFF]; + default: return NULL; + } +} #ifdef DEBUG #define M3OP(...) { __VA_ARGS__ } diff --git a/source/m3_core.h b/source/m3_core.h index e6598b9..ad0c646 100644 --- a/source/m3_core.h +++ b/source/m3_core.h @@ -47,6 +47,8 @@ typedef const char * const ccstr_t; typedef const u8 * bytes_t; typedef const u8 * const cbytes_t; +typedef u16 m3opcode_t; + typedef i64 m3reg_t; # if d_m3Use32BitSlots diff --git a/source/m3_exception.h b/source/m3_exception.h index 4a45741..3152db4 100644 --- a/source/m3_exception.h +++ b/source/m3_exception.h @@ -16,6 +16,7 @@ #define _try #define _(TRY) { result = TRY; if (result) { EXCEPTION_PRINT; goto _catch; } } #define _throw(ERROR) { result = ERROR; EXCEPTION_PRINT; goto _catch; } -#define _throwif(ERROR, COND) if (COND) { result = ERROR; EXCEPTION_PRINT; goto _catch; } +#define _throwif(ERROR, COND) if (UNLIKELY(COND)) \ + { result = ERROR; EXCEPTION_PRINT; goto _catch; } #endif // m3_exception_h diff --git a/source/m3_exec.h b/source/m3_exec.h index c487e90..ff66996 100644 --- a/source/m3_exec.h +++ b/source/m3_exec.h @@ -319,6 +319,16 @@ d_m3TruncMacro(_r0, _fp0, u64, Trunc, f32, OP_U64_TRUNC_F32) d_m3TruncMacro(_r0, _fp0, i64, Trunc, f64, OP_I64_TRUNC_F64) d_m3TruncMacro(_r0, _fp0, u64, Trunc, f64, OP_U64_TRUNC_F64) +d_m3TruncMacro(_r0, _fp0, i32, TruncSat, f32, OP_I32_TRUNC_SAT_F32) +d_m3TruncMacro(_r0, _fp0, u32, TruncSat, f32, OP_U32_TRUNC_SAT_F32) +d_m3TruncMacro(_r0, _fp0, i32, TruncSat, f64, OP_I32_TRUNC_SAT_F64) +d_m3TruncMacro(_r0, _fp0, u32, TruncSat, f64, OP_U32_TRUNC_SAT_F64) + +d_m3TruncMacro(_r0, _fp0, i64, TruncSat, f32, OP_I64_TRUNC_SAT_F32) +d_m3TruncMacro(_r0, _fp0, u64, TruncSat, f32, OP_U64_TRUNC_SAT_F32) +d_m3TruncMacro(_r0, _fp0, i64, TruncSat, f64, OP_I64_TRUNC_SAT_F64) +d_m3TruncMacro(_r0, _fp0, u64, TruncSat, f64, OP_U64_TRUNC_SAT_F64) + #define d_m3TypeModifyOp(REG_TO, REG_FROM, TO, NAME, FROM) \ d_m3Op(TO##_##NAME##_##FROM##_r) \ diff --git a/source/m3_info.c b/source/m3_info.c index f0b3760..f93ddf5 100644 --- a/source/m3_info.c +++ b/source/m3_info.c @@ -15,7 +15,7 @@ typedef struct OpInfo { IM3OpInfo info; - u8 opcode; + m3opcode_t opcode; } OpInfo; @@ -145,11 +145,12 @@ OpInfo find_operation_info (IM3Operation i_operation) { OpInfo opInfo = { NULL, 0 }; - if (i_operation) - { + if (!i_operation) return opInfo; + + // TODO: find also extended opcodes for (u32 i = 0; i <= 0xff; ++i) { - IM3OpInfo oi = & c_operations [i]; + IM3OpInfo oi = GetOpInfo(i); if (oi->type != c_m3Type_void) { @@ -165,7 +166,6 @@ OpInfo find_operation_info (IM3Operation i_operation) } else break; } - } return opInfo; } diff --git a/source/m3_math_utils.h b/source/m3_math_utils.h index 39def30..4f2e5c0 100644 --- a/source/m3_math_utils.h +++ b/source/m3_math_utils.h @@ -208,6 +208,27 @@ u64 rotr64(u64 n, unsigned c) { #define OP_I64_TRUNC_F64(RES, A) OP_TRUNC(RES, A, i64, -9223372036854777856.0 , 9223372036854775808.0 ) #define OP_U64_TRUNC_F64(RES, A) OP_TRUNC(RES, A, u64, -1.0 , 18446744073709551616.0 ) +#define OP_TRUNC_SAT(RES, A, TYPE, RMIN, RMAX) \ + if (UNLIKELY(isnan(A))) { \ + RES = (TYPE)0; \ + } else if (UNLIKELY(A <= RMIN)) { \ + RES = (TYPE)RMIN; \ + } else if (UNLIKELY(A >= RMAX)) { \ + RES = (TYPE)RMAX; \ + } else { \ + RES = (TYPE)A; \ + } + +#define OP_I32_TRUNC_SAT_F32(RES, A) OP_TRUNC_SAT(RES, A, i32, -2147483904.0f, 2147483648.0f) +#define OP_U32_TRUNC_SAT_F32(RES, A) OP_TRUNC_SAT(RES, A, u32, -1.0f, 4294967296.0f) +#define OP_I32_TRUNC_SAT_F64(RES, A) OP_TRUNC_SAT(RES, A, i32, -2147483649.0 , 2147483648.0 ) +#define OP_U32_TRUNC_SAT_F64(RES, A) OP_TRUNC_SAT(RES, A, u32, -1.0 , 4294967296.0 ) + +#define OP_I64_TRUNC_SAT_F32(RES, A) OP_TRUNC_SAT(RES, A, i64, -9223373136366403584.0f, 9223372036854775808.0f) +#define OP_U64_TRUNC_SAT_F32(RES, A) OP_TRUNC_SAT(RES, A, u64, -1.0f, 18446744073709551616.0f) +#define OP_I64_TRUNC_SAT_F64(RES, A) OP_TRUNC_SAT(RES, A, i64, -9223372036854777856.0 , 9223372036854775808.0 ) +#define OP_U64_TRUNC_SAT_F64(RES, A) OP_TRUNC_SAT(RES, A, u64, -1.0 , 18446744073709551616.0 ) + /* * Min, Max */