diff --git a/source/m3_bind.c b/source/m3_bind.c index 5864e5e..92d6429 100644 --- a/source/m3_bind.c +++ b/source/m3_bind.c @@ -6,8 +6,6 @@ // Copyright © 2019 Steven Massey. All rights reserved. // -#include - #include "m3_exec.h" #include "m3_env.h" #include "m3_exception.h" diff --git a/source/m3_code.c b/source/m3_code.c index e13de71..c58ef31 100644 --- a/source/m3_code.c +++ b/source/m3_code.c @@ -8,8 +8,6 @@ #include "m3_code.h" -#include - IM3CodePage NewCodePage (u32 i_minNumLines) { static u32 s_sequence = 0; diff --git a/source/m3_compile.c b/source/m3_compile.c index 3ef559b..add40eb 100644 --- a/source/m3_compile.c +++ b/source/m3_compile.c @@ -6,8 +6,6 @@ // Copyright © 2019 Steven Massey. All rights reserved. // -#include - #include "m3_compile.h" #include "m3_emit.h" #include "m3_exec.h" @@ -88,6 +86,10 @@ static const IM3Operation c_setSetOps [] = { NULL, op_SetSlot_i32, op_SetSlot_i6 #define none c_m3Type_none #define any (u8)-1 +bool IsStackPolymorphic (IM3Compilation o) +{ + return o->block.isPolymorphic; +} bool IsRegisterLocation (i16 i_location) { return (i_location >= c_m3Reg0SlotAlias); } bool IsFpRegisterLocation (i16 i_location) { return (i_location == c_m3Fp0SlotAlias); } @@ -151,6 +153,7 @@ i16 GetNumBlockValues (IM3Compilation o) return o->stackIndex - o->block.initStackIndex; } + bool IsStackTopInRegister (IM3Compilation o) { i16 i = GetStackTopIndex (o); d_m3Assert (i >= 0); @@ -163,11 +166,20 @@ bool IsStackTopInRegister (IM3Compilation o) } -u16 GetStackTopExecSlot (IM3Compilation o) +bool IsStackTopInSlot (IM3Compilation o) +{ + return not IsStackTopInRegister (o); +} + + +static const u16 c_slotUnused = 0xffff; + +u16 GetStackTopSlotIndex (IM3Compilation o) { i16 i = GetStackTopIndex (o); d_m3Assert (i >= 0); - u16 slot = 0; + u16 slot = c_slotUnused; + if (i >= 0) slot = o->wasmStack [i]; @@ -175,6 +187,12 @@ u16 GetStackTopExecSlot (IM3Compilation o) } +bool IsValidSlot (u16 i_slot) +{ + return (i_slot < d_m3MaxFunctionStackHeight); +} + + bool IsStackTopMinus1InRegister (IM3Compilation o) { i16 i = GetStackTopIndex (o); @@ -395,11 +413,8 @@ M3Result Pop (IM3Compilation o) m3logif (stack, dump_type_stack (o)) } - else - { - if (not o->block.isPolymorphic) - result = c_m3Err_functionStackUnderrun; - } + else if (not IsStackPolymorphic (o)) + result = c_m3Err_functionStackUnderrun; return result; } @@ -485,7 +500,7 @@ M3Result PushConst (IM3Compilation o, u64 i_word, u8 i_m3Type) o->constants [numConstants] = i_word; location = o->constSlotIndex++; - Push (o, i_m3Type, location); // stack check here?? + Push (o, i_m3Type, location); // stfack check here?? } else { @@ -501,8 +516,8 @@ _ (PushAllocatedSlotAndEmit (o, i_m3Type)); M3Result EmitTopSlotAndPop (IM3Compilation o) { - if (not IsStackTopInRegister (o)) - EmitConstant (o, GetStackTopExecSlot (o)); + if (IsStackTopInSlot (o)) + EmitConstant (o, GetStackTopSlotIndex (o)); return Pop (o); } @@ -538,8 +553,8 @@ M3Result CopyTopSlot (IM3Compilation o, u16 i_destSlot) _ (EmitOp (o, op)); EmitConstant (o, i_destSlot); - if (not IsStackTopInRegister (o)) - EmitConstant (o, GetStackTopExecSlot (o)); + if (IsStackTopInSlot (o)) + EmitConstant (o, GetStackTopSlotIndex (o)); _catch: return result; } @@ -565,8 +580,8 @@ M3Result PreservedCopyTopSlot (IM3Compilation o, u16 i_destSlot, u16 i_preserv _ (EmitOp (o, op)); EmitConstant (o, i_destSlot); - if (not IsStackTopInRegister (o)) - EmitConstant (o, GetStackTopExecSlot (o)); + if (IsStackTopInSlot (o)) + EmitConstant (o, GetStackTopSlotIndex (o)); EmitConstant (o, i_preserveSlot); @@ -579,7 +594,7 @@ M3Result MoveStackTopToRegister (IM3Compilation o) { M3Result result = c_m3Err_none; - if (not IsStackTopInRegister (o)) + if (IsStackTopInSlot (o)) { u8 type = GetStackTopType (o); @@ -610,7 +625,8 @@ M3Result ReturnStackTop (IM3Compilation o) if (o->wasmStack [top] != returnSlot) CopyTopSlot (o, returnSlot); } - else result = "stack underflow"; + else if (not IsStackPolymorphic (o)) + result = c_m3Err_functionStackUnderrun; return result; } @@ -852,7 +868,7 @@ _ (EmitOp (o, op)); EmitPointer (o, & i_global->intValue); if (op == op_SetGlobal_s) - EmitConstant (o, GetStackTopExecSlot (o)); + EmitConstant (o, GetStackTopSlotIndex (o)); _ (Pop (o)); @@ -906,34 +922,55 @@ _ (Pop (o)); } else op = op_ContinueLoop; -_ (PreserveRegisters (o)); - _ (EmitOp (o, op)); EmitPointer (o, scope->pc); } else { + u16 conditionSlot = c_slotUnused; + u16 valueSlot = c_slotUnused; + u8 valueType = scope->type; + if (i_opcode == c_waOp_branchIf) { -_ (MoveStackTopToRegister (o)); - op = op_BranchIf; -_ (Pop (o)); + bool conditionInRegister = IsStackTopInRegister (o); + + op = conditionInRegister ? op_BranchIf_r : op_BranchIf_s; // no block type or fp block type + + conditionSlot = GetStackTopSlotIndex (o); +_ (Pop (o)); // condition + + // no Pop of values here 'cause the next statement in block can consume this value + if (IsFpType (valueType)) + { +_ (MoveStackTopToRegister (o)); + } + else if (IsIntType (valueType)) + { + valueSlot = GetStackTopSlotIndex (o); + + const IM3Operation ifOps [2][2] = { { op_i32_BranchIf_ss, op_i32_BranchIf_rs }, { op_i64_BranchIf_ss, op_i64_BranchIf_rs } }; + + op = ifOps [valueType - c_m3Type_i32] [conditionInRegister]; + } } else { - if (GetNumBlockValues (o) > 0) -_ (MoveStackTopToRegister (o)); - op = op_Branch; - // smassey: some of the spec tests have opcodes after a unconditional branch. - // why? i don't know. i would consider this malformed Wasm code. - // but, so the compiler doesn't barf, we need to unwind the entire stack here. -_ (UnwindBlockStack (o)); + + if (scope->type != c_m3Type_none) +_ (MoveStackTopToRegister (o)); + +//_ (UnwindBlockStack (o)); o->block.isPolymorphic = true; } _ (EmitOp (o, op)); + if (IsValidSlot (conditionSlot)) + EmitConstant (o, conditionSlot); + if (IsValidSlot (valueSlot)) + EmitConstant (o, valueSlot); IM3BranchPatch patch = scope->patches; @@ -959,7 +996,7 @@ _ (ReadLEB_u32 (& targetCount, & o->wasm, o->wasmEnd)); _ (EnsureCodePageNumLines (o, numCodeLines)); _ (PreserveRegisterIfOccupied (o, c_m3Type_i64)); // move branch operand to a slot - u16 slot = GetStackTopExecSlot (o); + u16 slot = GetStackTopSlotIndex (o); _ (Pop (o)); @@ -1227,7 +1264,7 @@ M3Result Compile_Select (IM3Compilation o, u8 i_opcode) M3Result result = c_m3Err_none; - u16 slots [3] = { 0xffff, 0xffff, 0xffff }; + u16 slots [3] = { c_slotUnused, c_slotUnused, c_slotUnused }; u8 type = GetStackType (o, 1); // get type of selection @@ -1236,7 +1273,7 @@ M3Result Compile_Select (IM3Compilation o, u8 i_opcode) if (IsFpType (type)) { bool selectorInReg = IsStackTopInRegister (o); - slots [0] = GetStackTopExecSlot (o); + slots [0] = GetStackTopSlotIndex (o); _ (Pop (o)); u32 opIndex = 0; @@ -1246,7 +1283,7 @@ _ (Pop (o)); if (IsStackTopInRegister (o)) opIndex = i; else - slots [i] = GetStackTopExecSlot (o); + slots [i] = GetStackTopSlotIndex (o); _ (Pop (o)); } @@ -1266,7 +1303,7 @@ _ (PreserveRegisterIfOccupied (o, type)); if (IsStackTopInRegister (o)) opIndex = i; else - slots [i] = GetStackTopExecSlot (o); + slots [i] = GetStackTopSlotIndex (o); _ (Pop (o)); } @@ -1277,12 +1314,13 @@ _ (PreserveRegisterIfOccupied (o, type)); op = intSelectOps [type - c_m3Type_i32] [opIndex]; } - else _throw (c_m3Err_functionStackUnderrun); + else if (not IsStackPolymorphic (o)) + _throw (c_m3Err_functionStackUnderrun); EmitOp (o, op); for (u32 i = 0; i < 3; i++) { - if (slots [i] != 0xffff) + if (slots [i] != c_slotUnused) EmitConstant (o, slots [i]); } PushRegister (o, type); @@ -1421,7 +1459,7 @@ const M3OpInfo c_operations [] = M3OP( "end", 0, none, d_emptyOpList(), Compile_Else_End ), // 0x0b M3OP( "br", 0, none, d_singleOp (Branch), Compile_Branch ), // 0x0c - M3OP( "br_if", -1, none, d_emptyOpList(), Compile_Branch ), // 0x0d + M3OP( "br_if", -1, none, op_BranchIf_r, op_BranchIf_r, NULL, Compile_Branch ), // 0x0d M3OP( "br_table", -1, none, d_singleOp (BranchTable), Compile_BranchTable ), // 0x0e M3OP( "return", 0, any, d_singleOp (Return), Compile_Return ), // 0x0f M3OP( "call", 0, any, d_singleOp (Call), Compile_Call ), // 0x10 @@ -1695,7 +1733,7 @@ M3Result ValidateBlockEnd (IM3Compilation o, bool * o_copyStackTopToRegister) if (o->block.type != c_m3Type_none) { - if (o->block.isPolymorphic) + if (IsStackPolymorphic (o)) { _ (UnwindBlockStack (o)); PushRegister (o, o->block.type); @@ -1708,7 +1746,7 @@ _ (UnwindBlockStack (o)); { if (o->stackIndex == initStackIndex + 1) { - * o_copyStackTopToRegister = not IsStackTopInRegister (o); + * o_copyStackTopToRegister = IsStackTopInSlot (o); } else _throw ("unexpected block stack offset"); } diff --git a/source/m3_config.h b/source/m3_config.h index 1c441e8..e465b78 100644 --- a/source/m3_config.h +++ b/source/m3_config.h @@ -46,7 +46,7 @@ // It's enabled by default for Linux, OS X, Win32 and Android builds // and disabled on other platforms, i.e. microcontrollers # ifndef d_m3AllocateLinearMemory -# define d_m3AllocateLinearMemory false +# define d_m3AllocateLinearMemory 1 # endif # ifndef d_m3FixedHeapAlign @@ -63,14 +63,14 @@ // m3log (...) -------------------------------------------------------------------- -# define d_m3LogParse 0 -# define d_m3LogCompile 0 -# define d_m3LogStack 0 -# define d_m3LogEmit 0 -# define d_m3LogCodePages 0 +# define d_m3LogParse 1 +# define d_m3LogCompile 1 +# define d_m3LogStack 1 +# define d_m3LogEmit 1 +# define d_m3LogCodePages 1 # define d_m3LogModule 0 # define d_m3LogRuntime 0 -# define d_m3LogExec 0 +# define d_m3LogExec 1 # define d_m3LogNativeStack 0 diff --git a/source/m3_core.h b/source/m3_core.h index d82dec0..8efc71e 100644 --- a/source/m3_core.h +++ b/source/m3_core.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "m3.h" #include "m3_config.h" @@ -172,7 +173,6 @@ M3CodePageHeader; #define c_m3MemPageSize 65536 #define c_m3MaxFunctionStackHeight d_m3MaxFunctionStackHeight -#define c_m3MaxFunctionLocals 512 #define c_m3Reg0SlotAlias c_m3MaxFunctionStackHeight + 1 #define c_m3Fp0SlotAlias c_m3MaxFunctionStackHeight + 2 @@ -221,10 +221,10 @@ size_t m3StackGetMax (); #define m3StackGetMax() 0 #endif -void m3NotImplemented (); +void m3NotImplemented (void); void m3AbortIfNot (bool condition); -void m3Yield (); +void m3Yield (void); M3Result m3Malloc (void ** o_ptr, size_t i_size); void * m3Realloc (void * i_ptr, size_t i_newSize, size_t i_oldSize); diff --git a/source/m3_emit.c b/source/m3_emit.c index 5650355..f49f92b 100644 --- a/source/m3_emit.c +++ b/source/m3_emit.c @@ -59,7 +59,7 @@ void log_emit (IM3Operation i_operation) M3Result EmitOp (IM3Compilation o, IM3Operation i_operation) { - M3Result result = c_m3Err_none; + M3Result result = c_m3Err_none; d_m3Assert (i_operation); // it's OK for page to be null; when compile-walking the bytecode without emitting if (o->page) diff --git a/source/m3_env.c b/source/m3_env.c index 75fc86f..883fa04 100644 --- a/source/m3_env.c +++ b/source/m3_env.c @@ -6,7 +6,6 @@ // Copyright © 2019 Steven Massey. All rights reserved. // -#include #include #include "m3.h" diff --git a/source/m3_exec.h b/source/m3_exec.h index b08ebe3..7310467 100644 --- a/source/m3_exec.h +++ b/source/m3_exec.h @@ -471,7 +471,7 @@ d_m3Op (Bridge) } -d_m3Op (BranchIf) +d_m3Op (BranchIf_r) { i32 condition = (i32) _r0; pc_t branch = immediate (pc_t); @@ -484,6 +484,42 @@ d_m3Op (BranchIf) } +d_m3Op (BranchIf_s) +{ + i32 condition = slot (i32); + pc_t branch = immediate (pc_t); + + if (condition) + { + return jumpOp (branch); + } + else return nextOp (); +} + + +// branching to blocks that produce a (int) value +#define d_m3BranchIf(TYPE, LABEL, COND) \ +d_m3Op (TYPE##_BranchIf_##LABEL##s) \ +{ \ + i32 condition = (i32) COND; \ + TYPE value = slot (TYPE); \ + pc_t branch = immediate (pc_t); \ + \ + if (condition) \ + { \ + _r0 = value; \ + return jumpOp (branch); \ + } \ + else return nextOp (); \ +} + + +d_m3BranchIf (i32, r, _r0) +d_m3BranchIf (i64, r, _r0) +d_m3BranchIf (i32, s, slot (i32)) +d_m3BranchIf (i64, s, slot (i32)) + + d_m3OpDecl (BranchTable) diff --git a/source/m3_info.c b/source/m3_info.c index ca012fa..533f63c 100644 --- a/source/m3_info.c +++ b/source/m3_info.c @@ -9,8 +9,6 @@ #include "m3_info.h" #include "m3_compile.h" -#include - void m3_PrintM3Info () { printf ("\n-- m3 configuration --------------------------------------------\n"); diff --git a/source/m3_module.c b/source/m3_module.c index 42a9556..56b70b3 100644 --- a/source/m3_module.c +++ b/source/m3_module.c @@ -8,7 +8,6 @@ #include "m3_module.h" -#include void m3_FreeModule (IM3Module i_module) { diff --git a/test/run-spec-test.py b/test/run-spec-test.py index 01495d2..22273f5 100755 --- a/test/run-spec-test.py +++ b/test/run-spec-test.py @@ -469,14 +469,13 @@ else: "memory_redundancy", "float_memory", "memory", "memory_trap", "memory_grow", - "switch", "if", - "nop", - "start", + "unreachable", + "switch", "if", "br", + "nop", "start", #--- TODO --- - #"loop", "labels", "block", "br", "br_if", "br_table", "return", "unwind", + #"loop", "labels", "block", "br_if", "br_table", "return", "unwind", #"float_exprs", - #"unreachable", ])) for fn in jsonFiles: