207 lines
6.4 KiB
C
207 lines
6.4 KiB
C
//
|
|
// m3_compile.h
|
|
//
|
|
// Created by Steven Massey on 4/17/19.
|
|
// Copyright © 2019 Steven Massey. All rights reserved.
|
|
//
|
|
|
|
#ifndef m3_compile_h
|
|
#define m3_compile_h
|
|
|
|
#include "m3_code.h"
|
|
#include "m3_exec_defs.h"
|
|
#include "m3_function.h"
|
|
|
|
d_m3BeginExternC
|
|
|
|
enum
|
|
{
|
|
c_waOp_block = 0x02,
|
|
c_waOp_loop = 0x03,
|
|
c_waOp_if = 0x04,
|
|
c_waOp_else = 0x05,
|
|
c_waOp_end = 0x0b,
|
|
c_waOp_branch = 0x0c,
|
|
c_waOp_branchTable = 0x0e,
|
|
c_waOp_branchIf = 0x0d,
|
|
c_waOp_call = 0x10,
|
|
c_waOp_getLocal = 0x20,
|
|
c_waOp_setLocal = 0x21,
|
|
c_waOp_teeLocal = 0x22,
|
|
|
|
c_waOp_getGlobal = 0x23,
|
|
|
|
c_waOp_store_f32 = 0x38,
|
|
c_waOp_store_f64 = 0x39,
|
|
|
|
c_waOp_i32_const = 0x41,
|
|
c_waOp_i64_const = 0x42,
|
|
c_waOp_f32_const = 0x43,
|
|
c_waOp_f64_const = 0x44,
|
|
|
|
c_waOp_extended = 0xfc,
|
|
|
|
c_waOp_memoryCopy = 0xfc0a,
|
|
c_waOp_memoryFill = 0xfc0b
|
|
};
|
|
|
|
|
|
#define d_FuncRetType(ftype,i) ((ftype)->types[(i)])
|
|
#define d_FuncArgType(ftype,i) ((ftype)->types[(ftype)->numRets + (i)])
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
typedef struct M3CompilationScope
|
|
{
|
|
struct M3CompilationScope * outer;
|
|
|
|
pc_t pc; // used by ContinueLoop's
|
|
pc_t patches;
|
|
i32 depth;
|
|
u16 exitStackIndex;
|
|
i16 blockStackIndex;
|
|
// u16 topSlot;
|
|
IM3FuncType type;
|
|
m3opcode_t opcode;
|
|
bool isPolymorphic;
|
|
}
|
|
M3CompilationScope;
|
|
|
|
typedef M3CompilationScope * IM3CompilationScope;
|
|
|
|
typedef struct
|
|
{
|
|
IM3Runtime runtime;
|
|
IM3Module module;
|
|
|
|
bytes_t wasm;
|
|
bytes_t wasmEnd;
|
|
bytes_t lastOpcodeStart;
|
|
|
|
M3CompilationScope block;
|
|
|
|
IM3Function function;
|
|
|
|
IM3CodePage page;
|
|
|
|
#ifdef DEBUG
|
|
u32 numEmits;
|
|
u32 numOpcodes;
|
|
#endif
|
|
|
|
u16 stackFirstDynamicIndex; // args and locals are pushed to the stack so that their slot locations can be tracked. the wasm model itself doesn't
|
|
// treat these values as being on the stack, so stackFirstDynamicIndex marks the start of the real Wasm stack
|
|
u16 stackIndex; // current stack top
|
|
|
|
u16 slotFirstConstIndex;
|
|
u16 slotMaxConstIndex; // as const's are encountered during compilation this tracks their location in the "real" stack
|
|
|
|
u16 slotFirstLocalIndex;
|
|
u16 slotFirstDynamicIndex; // numArgs + numLocals + numReservedConstants. the first mutable slot available to the compiler.
|
|
|
|
u16 maxStackSlots;
|
|
|
|
m3slot_t constants [d_m3MaxConstantTableSize];
|
|
|
|
// 'wasmStack' holds slot locations
|
|
u16 wasmStack [d_m3MaxFunctionStackHeight];
|
|
u8 typeStack [d_m3MaxFunctionStackHeight];
|
|
|
|
// 'm3Slots' contains allocation usage counts
|
|
u8 m3Slots [d_m3MaxFunctionSlots];
|
|
|
|
u16 slotMaxAllocatedIndexPlusOne;
|
|
|
|
u16 regStackIndexPlusOne [2];
|
|
|
|
m3opcode_t previousOpcode;
|
|
}
|
|
M3Compilation;
|
|
|
|
typedef M3Compilation * IM3Compilation;
|
|
|
|
typedef M3Result (* M3Compiler) (IM3Compilation, m3opcode_t);
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
typedef struct M3OpInfo
|
|
{
|
|
#ifdef DEBUG
|
|
const char * const name;
|
|
#endif
|
|
|
|
i8 stackOffset;
|
|
u8 type;
|
|
|
|
// for most operations:
|
|
// [0]= top operand in register, [1]= top operand in stack, [2]= both operands in stack
|
|
IM3Operation operations [4];
|
|
|
|
M3Compiler compiler;
|
|
}
|
|
M3OpInfo;
|
|
|
|
typedef const M3OpInfo * IM3OpInfo;
|
|
|
|
IM3OpInfo GetOpInfo (m3opcode_t opcode);
|
|
|
|
// TODO: This helper should be removed, when MultiValue is implemented
|
|
static inline
|
|
u8 GetSingleRetType(IM3FuncType ftype) {
|
|
return (ftype && ftype->numRets) ? ftype->types[0] : (u8)c_m3Type_none;
|
|
}
|
|
|
|
static const u16 c_m3RegisterUnallocated = 0;
|
|
static const u16 c_slotUnused = 0xffff;
|
|
|
|
static inline
|
|
bool IsRegisterAllocated (IM3Compilation o, u32 i_register)
|
|
{
|
|
return (o->regStackIndexPlusOne [i_register] != c_m3RegisterUnallocated);
|
|
}
|
|
|
|
static inline
|
|
bool IsStackPolymorphic (IM3Compilation o)
|
|
{
|
|
return o->block.isPolymorphic;
|
|
}
|
|
|
|
static inline bool IsRegisterSlotAlias (u16 i_slot) { return (i_slot >= d_m3Reg0SlotAlias and i_slot != c_slotUnused); }
|
|
static inline bool IsFpRegisterSlotAlias (u16 i_slot) { return (i_slot == d_m3Fp0SlotAlias); }
|
|
static inline bool IsIntRegisterSlotAlias (u16 i_slot) { return (i_slot == d_m3Reg0SlotAlias); }
|
|
|
|
|
|
#ifdef DEBUG
|
|
#define M3OP(...) { __VA_ARGS__ }
|
|
#define M3OP_RESERVED { "reserved" }
|
|
#else
|
|
// Strip-off name
|
|
#define M3OP(name, ...) { __VA_ARGS__ }
|
|
#define M3OP_RESERVED { 0 }
|
|
#endif
|
|
|
|
#if d_m3HasFloat
|
|
#define M3OP_F M3OP
|
|
#elif d_m3NoFloatDynamic
|
|
#define M3OP_F(n,o,t,op,...) M3OP(n, o, t, { op_Unsupported, op_Unsupported, op_Unsupported, op_Unsupported }, __VA_ARGS__)
|
|
#else
|
|
#define M3OP_F(...) { 0 }
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
u16 GetMaxUsedSlotPlusOne (IM3Compilation o);
|
|
|
|
M3Result CompileBlock (IM3Compilation io, IM3FuncType i_blockType, m3opcode_t i_blockOpcode);
|
|
|
|
M3Result CompileBlockStatements (IM3Compilation io);
|
|
M3Result CompileFunction (IM3Function io_function);
|
|
|
|
M3Result CompileRawFunction (IM3Module io_module, IM3Function io_function, const void * i_function, const void * i_userdata);
|
|
|
|
d_m3EndExternC
|
|
|
|
#endif // m3_compile_h
|