1//
2// m3_compile.h
3//
4// Created by Steven Massey on 4/17/19.
5// Copyright © 2019 Steven Massey. All rights reserved.
6//
7
8#ifndef m3_compile_h
9#define m3_compile_h
10
11#include "m3_code.h"
12#include "m3_exec_defs.h"
13#include "m3_function.h"
14
15d_m3BeginExternC
16
17enum
18{
19 c_waOp_block = 0x02,
20 c_waOp_loop = 0x03,
21 c_waOp_if = 0x04,
22 c_waOp_else = 0x05,
23 c_waOp_end = 0x0b,
24 c_waOp_branch = 0x0c,
25 c_waOp_branchTable = 0x0e,
26 c_waOp_branchIf = 0x0d,
27 c_waOp_call = 0x10,
28 c_waOp_getLocal = 0x20,
29 c_waOp_setLocal = 0x21,
30 c_waOp_teeLocal = 0x22,
31
32 c_waOp_getGlobal = 0x23,
33
34 c_waOp_store_f32 = 0x38,
35 c_waOp_store_f64 = 0x39,
36
37 c_waOp_i32_const = 0x41,
38 c_waOp_i64_const = 0x42,
39 c_waOp_f32_const = 0x43,
40 c_waOp_f64_const = 0x44,
41
42 c_waOp_extended = 0xfc,
43
44 c_waOp_memoryCopy = 0xfc0a,
45 c_waOp_memoryFill = 0xfc0b
46};
47
48
49#define d_FuncRetType(ftype,i) ((ftype)->types[(i)])
50#define d_FuncArgType(ftype,i) ((ftype)->types[(ftype)->numRets + (i)])
51
52//-----------------------------------------------------------------------------------------------------------------------------------
53
54typedef struct M3CompilationScope
55{
56 struct M3CompilationScope * outer;
57
58 pc_t pc; // used by ContinueLoop's
59 pc_t patches;
60 i32 depth;
61 u16 exitStackIndex;
62 i16 blockStackIndex;
63// u16 topSlot;
64 IM3FuncType type;
65 m3opcode_t opcode;
66 bool isPolymorphic;
67}
68M3CompilationScope;
69
70typedef M3CompilationScope * IM3CompilationScope;
71
72typedef struct
73{
74 IM3Runtime runtime;
75 IM3Module module;
76
77 bytes_t wasm;
78 bytes_t wasmEnd;
79 bytes_t lastOpcodeStart;
80
81 M3CompilationScope block;
82
83 IM3Function function;
84
85 IM3CodePage page;
86
87#ifdef DEBUG
88 u32 numEmits;
89 u32 numOpcodes;
90#endif
91
92 u16 stackFirstDynamicIndex; // args and locals are pushed to the stack so that their slot locations can be tracked. the wasm model itself doesn't
93 // treat these values as being on the stack, so stackFirstDynamicIndex marks the start of the real Wasm stack
94 u16 stackIndex; // current stack top
95
96 u16 slotFirstConstIndex;
97 u16 slotMaxConstIndex; // as const's are encountered during compilation this tracks their location in the "real" stack
98
99 u16 slotFirstLocalIndex;
100 u16 slotFirstDynamicIndex; // numArgs + numLocals + numReservedConstants. the first mutable slot available to the compiler.
101
102 u16 maxStackSlots;
103
104 m3slot_t constants [d_m3MaxConstantTableSize];
105
106 // 'wasmStack' holds slot locations
107 u16 wasmStack [d_m3MaxFunctionStackHeight];
108 u8 typeStack [d_m3MaxFunctionStackHeight];
109
110 // 'm3Slots' contains allocation usage counts
111 u8 m3Slots [d_m3MaxFunctionSlots];
112
113 u16 slotMaxAllocatedIndexPlusOne;
114
115 u16 regStackIndexPlusOne [2];
116
117 m3opcode_t previousOpcode;
118}
119M3Compilation;
120
121typedef M3Compilation * IM3Compilation;
122
123typedef M3Result (* M3Compiler) (IM3Compilation, m3opcode_t);
124
125
126//-----------------------------------------------------------------------------------------------------------------------------------
127
128
129typedef struct M3OpInfo
130{
131#ifdef DEBUG
132 const char * const name;
133#endif
134
135 i8 stackOffset;
136 u8 type;
137
138 // for most operations:
139 // [0]= top operand in register, [1]= top operand in stack, [2]= both operands in stack
140 IM3Operation operations [4];
141
142 M3Compiler compiler;
143}
144M3OpInfo;
145
146typedef const M3OpInfo * IM3OpInfo;
147
148IM3OpInfo GetOpInfo (m3opcode_t opcode);
149
150// TODO: This helper should be removed, when MultiValue is implemented
151static inline
152u8 GetSingleRetType(IM3FuncType ftype) {
153 return (ftype && ftype->numRets) ? ftype->types[0] : (u8)c_m3Type_none;
154}
155
156static const u16 c_m3RegisterUnallocated = 0;
157static const u16 c_slotUnused = 0xffff;
158
159static inline
160bool IsRegisterAllocated (IM3Compilation o, u32 i_register)
161{
162 return (o->regStackIndexPlusOne [i_register] != c_m3RegisterUnallocated);
163}
164
165static inline
166bool IsStackPolymorphic (IM3Compilation o)
167{
168 return o->block.isPolymorphic;
169}
170
171static inline bool IsRegisterSlotAlias (u16 i_slot) { return (i_slot >= d_m3Reg0SlotAlias and i_slot != c_slotUnused); }
172static inline bool IsFpRegisterSlotAlias (u16 i_slot) { return (i_slot == d_m3Fp0SlotAlias); }
173static inline bool IsIntRegisterSlotAlias (u16 i_slot) { return (i_slot == d_m3Reg0SlotAlias); }
174
175
176#ifdef DEBUG
177 #define M3OP(...) { __VA_ARGS__ }
178 #define M3OP_RESERVED { "reserved" }
179#else
180 // Strip-off name
181 #define M3OP(name, ...) { __VA_ARGS__ }
182 #define M3OP_RESERVED { 0 }
183#endif
184
185#if d_m3HasFloat
186 #define M3OP_F M3OP
187#elif d_m3NoFloatDynamic
188 #define M3OP_F(n,o,t,op,...) M3OP(n, o, t, { op_Unsupported, op_Unsupported, op_Unsupported, op_Unsupported }, __VA_ARGS__)
189#else
190 #define M3OP_F(...) { 0 }
191#endif
192
193//-----------------------------------------------------------------------------------------------------------------------------------
194
195u16 GetMaxUsedSlotPlusOne (IM3Compilation o);
196
197M3Result CompileBlock (IM3Compilation io, IM3FuncType i_blockType, m3opcode_t i_blockOpcode);
198
199M3Result CompileBlockStatements (IM3Compilation io);
200M3Result CompileFunction (IM3Function io_function);
201
202M3Result CompileRawFunction (IM3Module io_module, IM3Function io_function, const void * i_function, const void * i_userdata);
203
204d_m3EndExternC
205
206#endif // m3_compile_h
207