|
|
|
@ -198,6 +198,11 @@ bool IsRegisterAllocated (IM3Compilation o, u32 i_register)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool IsRegisterTypeAllocated (IM3Compilation o, u8 i_type)
|
|
|
|
|
{
|
|
|
|
|
return IsRegisterAllocated (o, IsFpType (i_type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AllocateRegister (IM3Compilation o, u32 i_register, u16 i_stackIndex)
|
|
|
|
|
{ d_m3Assert (not IsRegisterAllocated (o, i_register));
|
|
|
|
|
o->regStackIndexPlusOne [i_register] = i_stackIndex + 1;
|
|
|
|
@ -1356,7 +1361,8 @@ _ (PreserveRegisterIfOccupied (o, type));
|
|
|
|
|
EmitOp (o, op);
|
|
|
|
|
for (u32 i = 0; i < 3; i++)
|
|
|
|
|
{
|
|
|
|
|
if (slots [i] != c_slotUnused)
|
|
|
|
|
if (IsValidSlot (slots [i]))
|
|
|
|
|
// if (slots [i] != c_slotUnused)
|
|
|
|
|
EmitConstant (o, slots [i]);
|
|
|
|
|
}
|
|
|
|
|
_ (PushRegister (o, type));
|
|
|
|
@ -1406,32 +1412,32 @@ M3Result Compile_Operator (IM3Compilation o, u8 i_opcode)
|
|
|
|
|
{
|
|
|
|
|
if (IsStackTopInRegister (o))
|
|
|
|
|
{
|
|
|
|
|
operation = op->operation_sr;
|
|
|
|
|
operation = op->operations [0];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_ (PreserveRegisterIfOccupied (o, op->type));
|
|
|
|
|
operation = op->operation_rs;
|
|
|
|
|
operation = op->operations [1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (IsStackTopInRegister (o))
|
|
|
|
|
{
|
|
|
|
|
operation = op->operation_sr; // printf ("r <- s+r\n");
|
|
|
|
|
operation = op->operations [0]; // printf ("r <- s+r\n");
|
|
|
|
|
}
|
|
|
|
|
else if (IsStackTopMinus1InRegister (o))
|
|
|
|
|
{
|
|
|
|
|
operation = op->operation_rs;
|
|
|
|
|
operation = op->operations [1];
|
|
|
|
|
|
|
|
|
|
if (not operation) // must be commutative, then
|
|
|
|
|
operation = op->operation_sr;
|
|
|
|
|
operation = op->operations [0];
|
|
|
|
|
// printf ("r <- r+s\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_ (PreserveRegisterIfOccupied (o, op->type));
|
|
|
|
|
operation = op->operation_ss; // printf ("r <- s+s\n");
|
|
|
|
|
operation = op->operations [2]; // printf ("r <- s+s\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1439,8 +1445,6 @@ _ (PreserveRegisterIfOccupied (o, op->type));
|
|
|
|
|
{
|
|
|
|
|
_ (EmitOp (o, operation));
|
|
|
|
|
|
|
|
|
|
// if (op->type != c_m3Type_none)
|
|
|
|
|
{
|
|
|
|
|
_ (EmitTopSlotAndPop (o));
|
|
|
|
|
|
|
|
|
|
if (op->stackOffset < 0)
|
|
|
|
@ -1449,16 +1453,39 @@ _ (EmitTopSlotAndPop (o));
|
|
|
|
|
if (op->type != c_m3Type_none)
|
|
|
|
|
_ (PushRegister (o, op->type));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result = ErrorCompile ("no operation", o, "'%s'", op->name);
|
|
|
|
|
result = ErrorCompile ("no operation found for opcode", o, "'%s'", op->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_catch: return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
M3Result Compile_Convert (IM3Compilation o, u8 i_opcode)
|
|
|
|
|
{
|
|
|
|
|
M3Result result = c_m3Err_none;
|
|
|
|
|
|
|
|
|
|
const M3OpInfo * opInfo = & c_operations [i_opcode];
|
|
|
|
|
|
|
|
|
|
bool destInSlot = IsRegisterTypeAllocated (o, opInfo->type);
|
|
|
|
|
bool sourceInSlot = IsStackTopInSlot (o);
|
|
|
|
|
|
|
|
|
|
IM3Operation op = opInfo->operations [destInSlot * 2 + sourceInSlot];
|
|
|
|
|
|
|
|
|
|
_ (EmitOp (o, op));
|
|
|
|
|
_ (EmitTopSlotAndPop (o));
|
|
|
|
|
|
|
|
|
|
if (destInSlot)
|
|
|
|
|
_ (PushAllocatedSlotAndEmit (o, opInfo->type))
|
|
|
|
|
else
|
|
|
|
|
_ (PushRegister (o, opInfo->type))
|
|
|
|
|
|
|
|
|
|
_catch: return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
M3Result Compile_Load_Store (IM3Compilation o, u8 i_opcode)
|
|
|
|
|
{
|
|
|
|
|
M3Result result;
|
|
|
|
@ -1468,6 +1495,11 @@ M3Result Compile_Load_Store (IM3Compilation o, u8 i_opcode)
|
|
|
|
|
_ (ReadLEB_u32 (& alignHint, & o->wasm, o->wasmEnd));
|
|
|
|
|
_ (ReadLEB_u32 (& offset, & o->wasm, o->wasmEnd));
|
|
|
|
|
m3log (compile, d_indent "%s (offset = %d)", get_indention_string (o), offset);
|
|
|
|
|
const M3OpInfo * op = & c_operations [i_opcode];
|
|
|
|
|
|
|
|
|
|
if (IsFpType (op->type))
|
|
|
|
|
_ (PreserveRegisterIfOccupied (o, c_m3Type_f64));
|
|
|
|
|
|
|
|
|
|
_ (Compile_Operator (o, i_opcode));
|
|
|
|
|
EmitConstant (o, offset);
|
|
|
|
|
|
|
|
|
@ -1475,12 +1507,13 @@ _ (Compile_Operator (o, i_opcode));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define d_singleOp(OP) op_##OP, NULL, NULL // these aren't actually used by the compiler, just codepage decoding
|
|
|
|
|
#define d_emptyOpList() NULL, NULL, NULL
|
|
|
|
|
#define d_unaryOpList(TYPE, NAME) op_##TYPE##_##NAME##_r, op_##TYPE##_##NAME##_s, NULL
|
|
|
|
|
#define d_binOpList(TYPE, NAME) op_##TYPE##_##NAME##_sr, op_##TYPE##_##NAME##_rs, op_##TYPE##_##NAME##_ss
|
|
|
|
|
#define d_commutativeBinOpList(TYPE, NAME) op_##TYPE##_##NAME##_sr, NULL, op_##TYPE##_##NAME##_ss
|
|
|
|
|
#define d_singleOp(OP) { op_##OP, NULL, NULL, NULL } // these aren't actually used by the compiler, just codepage decoding
|
|
|
|
|
#define d_emptyOpList() { NULL, NULL, NULL, NULL }
|
|
|
|
|
#define d_unaryOpList(TYPE, NAME) { op_##TYPE##_##NAME##_r, op_##TYPE##_##NAME##_s, NULL, NULL }
|
|
|
|
|
#define d_binOpList(TYPE, NAME) { op_##TYPE##_##NAME##_sr, op_##TYPE##_##NAME##_rs, op_##TYPE##_##NAME##_ss, NULL }
|
|
|
|
|
#define d_commutativeBinOpList(TYPE, NAME) { op_##TYPE##_##NAME##_sr, NULL, op_##TYPE##_##NAME##_ss, NULL }
|
|
|
|
|
|
|
|
|
|
#define d_convertOpList(OP) { op_##OP##_r_r, op_##OP##_r_s, op_##OP##_s_r, op_##OP##_s_s }
|
|
|
|
|
|
|
|
|
|
const M3OpInfo c_operations [] =
|
|
|
|
|
{
|
|
|
|
@ -1495,7 +1528,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, op_BranchIf_r, op_BranchIf_s, NULL, Compile_Branch ), // 0x0d
|
|
|
|
|
M3OP( "br_if", -1, none, { op_BranchIf_r, op_BranchIf_s, NULL, 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
|
|
|
|
@ -1667,64 +1700,58 @@ const M3OpInfo c_operations [] =
|
|
|
|
|
M3OP( "f64.copysign", -1, f_64, d_binOpList (f64, CopySign) ), // 0xa6
|
|
|
|
|
|
|
|
|
|
M3OP( "i32.wrap/i64", 0, i_32, d_unaryOpList (i32, Wrap_i64) ), // 0xa7
|
|
|
|
|
M3OP( "i32.trunc_s/f32", 0, i_32, d_unaryOpList(i32, Trunc_f32) ), // 0xa8
|
|
|
|
|
M3OP( "i32.trunc_u/f32", 0, i_32, d_unaryOpList(u32, Trunc_f32) ), // 0xa9
|
|
|
|
|
M3OP( "i32.trunc_s/f64", 0, i_32, d_unaryOpList(i32, Trunc_f64) ), // 0xaa
|
|
|
|
|
M3OP( "i32.trunc_u/f64", 0, i_32, d_unaryOpList(u32, Trunc_f64) ), // 0xab
|
|
|
|
|
M3OP( "i32.trunc_s/f32", 0, i_32, d_convertOpList (i32_Trunc_f32), Compile_Convert ), // 0xa8
|
|
|
|
|
M3OP( "i32.trunc_u/f32", 0, i_32, d_convertOpList (u32_Trunc_f32), Compile_Convert ), // 0xa9
|
|
|
|
|
M3OP( "i32.trunc_s/f64", 0, i_32, d_convertOpList (i32_Trunc_f64), Compile_Convert ), // 0xaa
|
|
|
|
|
M3OP( "i32.trunc_u/f64", 0, i_32, d_convertOpList (u32_Trunc_f64), Compile_Convert ), // 0xab
|
|
|
|
|
|
|
|
|
|
M3OP( "i64.extend_s/i32", 0, i_64, d_unaryOpList (i64, Extend_i32) ), // 0xac
|
|
|
|
|
M3OP( "i64.extend_u/i32", 0, i_64, d_unaryOpList (i64, Extend_u32) ), // 0xad
|
|
|
|
|
M3OP( "i64.trunc_s/f32", 0, i_64, d_unaryOpList(i64, Trunc_f32) ), // 0xae
|
|
|
|
|
M3OP( "i64.trunc_u/f32", 0, i_64, d_unaryOpList(u64, Trunc_f32) ), // 0xaf
|
|
|
|
|
M3OP( "i64.trunc_s/f64", 0, i_64, d_unaryOpList(i64, Trunc_f64) ), // 0xb0
|
|
|
|
|
M3OP( "i64.trunc_u/f64", 0, i_64, d_unaryOpList(u64, Trunc_f64) ), // 0xb1
|
|
|
|
|
|
|
|
|
|
M3OP( "f32.convert_s/i32", 0, f_32, d_unaryOpList(f32, Convert_i32) ), // 0xb2
|
|
|
|
|
M3OP( "f32.convert_u/i32", 0, f_32, d_unaryOpList(f32, Convert_u32) ), // 0xb3
|
|
|
|
|
M3OP( "f32.convert_s/i64", 0, f_32, d_unaryOpList(f32, Convert_i64) ), // 0xb4
|
|
|
|
|
M3OP( "f32.convert_u/i64", 0, f_32, d_unaryOpList(f32, Convert_u64) ), // 0xb5
|
|
|
|
|
|
|
|
|
|
M3OP( "i64.trunc_s/f32", 0, i_64, d_convertOpList (i64_Trunc_f32), Compile_Convert ), // 0xae
|
|
|
|
|
M3OP( "i64.trunc_u/f32", 0, i_64, d_convertOpList (u64_Trunc_f32), Compile_Convert ), // 0xaf
|
|
|
|
|
M3OP( "i64.trunc_s/f64", 0, i_64, d_convertOpList (i64_Trunc_f64), Compile_Convert ), // 0xb0
|
|
|
|
|
M3OP( "i64.trunc_u/f64", 0, i_64, d_convertOpList (u64_Trunc_f64), Compile_Convert ), // 0xb1
|
|
|
|
|
|
|
|
|
|
M3OP( "f32.convert_s/i32", 0, f_32, d_convertOpList (f32_Convert_i32), Compile_Convert ), // 0xb2
|
|
|
|
|
M3OP( "f32.convert_u/i32", 0, f_32, d_convertOpList (f32_Convert_u32), Compile_Convert ), // 0xb3
|
|
|
|
|
M3OP( "f32.convert_s/i64", 0, f_32, d_convertOpList (f32_Convert_i64), Compile_Convert ), // 0xb4
|
|
|
|
|
M3OP( "f32.convert_u/i64", 0, f_32, d_convertOpList (f32_Convert_u64), Compile_Convert ), // 0xb5
|
|
|
|
|
|
|
|
|
|
M3OP( "f32.demote/f64", 0, f_32, d_unaryOpList (f32, Demote_f64) ), // 0xb6
|
|
|
|
|
|
|
|
|
|
M3OP( "f64.convert_s/i32", 0, f_64, d_unaryOpList(f64, Convert_i32) ), // 0xb7
|
|
|
|
|
M3OP( "f64.convert_u/i32", 0, f_64, d_unaryOpList(f64, Convert_u32) ), // 0xb8
|
|
|
|
|
M3OP( "f64.convert_s/i64", 0, f_64, d_unaryOpList(f64, Convert_i64) ), // 0xb9
|
|
|
|
|
M3OP( "f64.convert_u/i64", 0, f_64, d_unaryOpList(f64, Convert_u64) ), // 0xba
|
|
|
|
|
M3OP( "f64.convert_s/i32", 0, f_64, d_convertOpList (f64_Convert_i32), Compile_Convert ), // 0xb7
|
|
|
|
|
M3OP( "f64.convert_u/i32", 0, f_64, d_convertOpList (f64_Convert_u32), Compile_Convert ), // 0xb8
|
|
|
|
|
M3OP( "f64.convert_s/i64", 0, f_64, d_convertOpList (f64_Convert_i64), Compile_Convert ), // 0xb9
|
|
|
|
|
M3OP( "f64.convert_u/i64", 0, f_64, d_convertOpList (f64_Convert_u64), Compile_Convert ), // 0xba
|
|
|
|
|
|
|
|
|
|
M3OP( "f64.promote/f32", 0, f_64, d_unaryOpList (f64, Promote_f32) ), // 0xbb
|
|
|
|
|
|
|
|
|
|
M3OP( "i32.reinterpret/f32", 0, i_32, d_unaryOpList(i32, Reinterpret_f32) ), // 0xbc
|
|
|
|
|
M3OP( "i64.reinterpret/f64", 0, i_64, d_unaryOpList(i64, Reinterpret_f64) ), // 0xbd
|
|
|
|
|
M3OP( "f32.reinterpret/i32", 0, f_32, d_unaryOpList(f32, Reinterpret_i32) ), // 0xbe
|
|
|
|
|
M3OP( "f64.reinterpret/i64", 0, f_64, d_unaryOpList(f64, Reinterpret_i64) ), // 0xbf
|
|
|
|
|
M3OP( "i32.reinterpret/f32", 0, i_32, d_convertOpList (i32_Reinterpret_f32), Compile_Convert ), // 0xbc
|
|
|
|
|
M3OP( "i64.reinterpret/f64", 0, i_64, d_convertOpList (i64_Reinterpret_f64), Compile_Convert ), // 0xbd
|
|
|
|
|
M3OP( "f32.reinterpret/i32", 0, f_32, d_convertOpList (f32_Reinterpret_i32), Compile_Convert ), // 0xbe
|
|
|
|
|
M3OP( "f64.reinterpret/i64", 0, f_64, d_convertOpList (f64_Reinterpret_i64), Compile_Convert ), // 0xbf
|
|
|
|
|
|
|
|
|
|
# ifdef DEBUG // for codepage logging:
|
|
|
|
|
M3OP( "Const", 1, any, op_Const ),
|
|
|
|
|
M3OP( "Entry", 0, none, op_Entry ),
|
|
|
|
|
M3OP( "Compile", 0, none, op_Compile),
|
|
|
|
|
M3OP( "Bridge", 0, none, op_Bridge),
|
|
|
|
|
|
|
|
|
|
M3OP( "SetGlobal_s", 0, none, op_SetGlobal_s),
|
|
|
|
|
|
|
|
|
|
M3OP( "ContinueLoop", 0, none, op_ContinueLoop),
|
|
|
|
|
M3OP( "ContinueLoopIf", 0, none, op_ContinueLoopIf),
|
|
|
|
|
|
|
|
|
|
M3OP( "PreserveCopySlot", 0, none, op_PreserveCopySlot_64),
|
|
|
|
|
M3OP( "CopySlot", 0, none, op_CopySlot_64),
|
|
|
|
|
M3OP( "SetSlot_i32", 0, none, op_SetSlot_i32),
|
|
|
|
|
M3OP( "SetSlot_i64", 0, none, op_SetSlot_i64),
|
|
|
|
|
M3OP( "SetSlot_f32", 0, none, op_SetSlot_f32),
|
|
|
|
|
M3OP( "SetSlot_f64", 0, none, op_SetSlot_f64),
|
|
|
|
|
|
|
|
|
|
M3OP( "SetRegister_i32", 0, none, op_SetRegister_i32),
|
|
|
|
|
M3OP( "SetRegister_i64", 0, none, op_SetRegister_i64),
|
|
|
|
|
M3OP( "SetRegister_f32", 0, none, op_SetRegister_f32),
|
|
|
|
|
M3OP( "SetRegister_f64", 0, none, op_SetRegister_f64),
|
|
|
|
|
|
|
|
|
|
M3OP( "i32_BranchIf_rs", 0, none, op_i32_BranchIf_rs),
|
|
|
|
|
M3OP( "i32_BranchIf_ss", 0, none, op_i32_BranchIf_ss),
|
|
|
|
|
M3OP( "i64_BranchIf_rs", 0, none, op_i64_BranchIf_rs),
|
|
|
|
|
M3OP( "i64_BranchIf_ss", 0, none, op_i64_BranchIf_ss),
|
|
|
|
|
|
|
|
|
|
M3OP( "End", 0, none, op_End ),
|
|
|
|
|
# define d_m3DebugOp(OP) M3OP (#OP, 0, none, op_##OP)
|
|
|
|
|
|
|
|
|
|
d_m3DebugOp (Const), d_m3DebugOp (Entry), d_m3DebugOp (Compile),
|
|
|
|
|
d_m3DebugOp (Bridge), d_m3DebugOp (End), d_m3DebugOp (SetGlobal_s),
|
|
|
|
|
|
|
|
|
|
d_m3DebugOp (ContinueLoop), d_m3DebugOp (ContinueLoopIf),
|
|
|
|
|
|
|
|
|
|
d_m3DebugOp (CopySlot_64), d_m3DebugOp (PreserveCopySlot_64),
|
|
|
|
|
|
|
|
|
|
d_m3DebugOp (SetSlot_i32),
|
|
|
|
|
d_m3DebugOp (SetSlot_i64),
|
|
|
|
|
d_m3DebugOp (SetSlot_f32),
|
|
|
|
|
d_m3DebugOp (SetSlot_f64),
|
|
|
|
|
|
|
|
|
|
d_m3DebugOp (SetRegister_i32), d_m3DebugOp (i32_BranchIf_rs),
|
|
|
|
|
d_m3DebugOp (SetRegister_i64), d_m3DebugOp (i32_BranchIf_ss),
|
|
|
|
|
d_m3DebugOp (SetRegister_f32), d_m3DebugOp (i64_BranchIf_rs),
|
|
|
|
|
d_m3DebugOp (SetRegister_f64), d_m3DebugOp (i64_BranchIf_ss),
|
|
|
|
|
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
M3OP( "termination", 0, c_m3Type_void ) // termination for find_operation_info ()
|
|
|
|
|