br_if progress

extensions
Steven Massey 5 years ago
parent be51568353
commit 2e1cbaa32a

@ -6,8 +6,6 @@
// Copyright © 2019 Steven Massey. All rights reserved.
//
#include <assert.h>
#include "m3_exec.h"
#include "m3_env.h"
#include "m3_exception.h"

@ -8,8 +8,6 @@
#include "m3_code.h"
#include <assert.h>
IM3CodePage NewCodePage (u32 i_minNumLines)
{
static u32 s_sequence = 0;

@ -6,8 +6,6 @@
// Copyright © 2019 Steven Massey. All rights reserved.
//
#include <assert.h>
#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");
}

@ -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

@ -10,6 +10,7 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#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);

@ -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)

@ -6,7 +6,6 @@
// Copyright © 2019 Steven Massey. All rights reserved.
//
#include <assert.h>
#include <stdarg.h>
#include "m3.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)

@ -9,8 +9,6 @@
#include "m3_info.h"
#include "m3_compile.h"
#include <assert.h>
void m3_PrintM3Info ()
{
printf ("\n-- m3 configuration --------------------------------------------\n");

@ -8,7 +8,6 @@
#include "m3_module.h"
#include <assert.h>
void m3_FreeModule (IM3Module i_module)
{

@ -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:

Loading…
Cancel
Save