#include <stdbool.h> #include "wasm_compile.h" #define DATA_NONE 0 #define DATA_KNOWN 1 #define DATA_KNOWN_21_BITS 2 #define DATA_KNOWN_6_BITS 3 #define DATA_INSTR_ADDR 4 #define DATA_ADDR_AFTER 5 struct instruction_data { char info; union { uint32_t im; struct instruction **ptr; } data; }; struct instruction { struct instruction *prev, *next; uint32_t address; bool address_assigned; uint16_t encoding; struct instruction_data data; const char *name; }; #define NO_DATA ((struct instruction_data) { \ .info = DATA_NONE \ }) inline static uint8_t im_instruction_size(int32_t im) { if (im < POW(6) && im >= -POW(6)) return 2; else if (im < POW(21) && im >= -POW(21)) return 4; else return 6; } inline static struct instruction_data im(uint32_t im) { struct instruction_data data; data.data.im = im; uint8_t size = im_instruction_size(im); if (size == 2) data.info = DATA_KNOWN_6_BITS; else if (size == 4) data.info = DATA_KNOWN_21_BITS; else data.info = DATA_KNOWN; return data; } inline static struct instruction_data ptr(struct instruction **val) { struct instruction_data data; data.info = DATA_INSTR_ADDR; data.data.ptr = val; return data; } inline static struct instruction_data ptr_after(struct instruction **val) { struct instruction_data data; data.info = DATA_ADDR_AFTER; data.data.ptr = val; return data; } int add_instruction(struct instruction **expr, uint16_t encoding, struct instruction_data data, const char *name); /* Define stack machine instructions, that take immediate operands */ #define X(instr, encoding) \ inline static int i_##instr(struct instruction_data data, \ struct instruction **expr) \ { \ return add_instruction(expr, encoding, data, #instr); \ } /* Define stack machine instructions, that *don't* take immediate operands */ #define Y(instr, encoding) \ inline static int i_##instr(struct instruction **expr) \ { \ return add_instruction(expr, encoding, NO_DATA, #instr); \ } X(store, 0x7E00) /* 0111_1110_0xxx_xxxx */ X(store_p, 0x6E00) /* 0110_1110_0xxx_xxxx */ X(storeb_p, 0x6C00) /* 0110_1100_0xxx_xxxx */ X(storew_p, 0x6D00) /* 0110_1101_0xxx_xxxx */ X(load, 0x5E00) /* 0101_1110_0xxx_xxxx */ X(load_p, 0x4E00) /* 0100_1110_0xxx_xxxx */ X(loadbzx_p, 0x4C00) /* 0100_1100_0xxx_xxxx */ X(loadbsx_p, 0x4C80) /* 0100_1100_1xxx_xxxx */ X(loadwzx_p, 0x4D00) /* 0100_1101_0xxx_xxxx */ X(loadwsx_p, 0x4D80) /* 0100_1101_1xxx_xxxx */ Y(nop, 0x0001) /* 0000_0000_0000_0001 */ Y(swap, 0x0002) /* 0000_0000_0000_0010 */ X(set_sp, 0x4000) /* 0100_0000_0xxx_xxxx */ X(jump, 0x4080) /* 0100_0000_1xxx_xxxx */ X(add_sp, 0x4100) /* 0100_0001_0xxx_xxxx */ Y(tee, 0x1000) /* 0001_0000_0000_0000 */ Y(get_frame, 0x1001) /* 0001_0000_0000_0001 */ X(const, 0x5000) /* 0101_0000_0xxx_xxxx */ X(call, 0x5080) /* 0101_0000_1xxx_xxxx */ Y(add, 0x3000) /* 0011_0000_0000_0000 */ Y(sub, 0x3001) /* 0011_0000_0000_0001 */ Y(div, 0x3002) /* 0011_0000_0000_0010 */ Y(mul, 0x3003) /* 0011_0000_0000_0011 */ Y(drop, 0x3004) /* 0011_0000_0000_0100 */ Y(eq, 0x3007) /* 0011_0000_0000_0111 */ Y(lt, 0x3008) /* 0011_0000_0000_1000 */ Y(ult, 0x3009) /* 0011_0000_0000_1001 */ Y(le, 0x300A) /* 0011_0000_0000_1010 */ Y(ule, 0x300B) /* 0011_0000_0000_1011 */ Y(gt, 0x300C) /* 0011_0000_0000_1100 */ Y(ugt, 0x300D) /* 0011_0000_0000_1101 */ Y(ge, 0x300E) /* 0011_0000_0000_1110 */ Y(uge, 0x300F) /* 0011_0000_0000_1111 */ Y(rem, 0x3010) /* 0011_0000_0001_0000 */ Y(ret, 0x3080) /* 0011_0000_1000_0000 */ X(cond_jump, 0x7080) /* 0111_0000_1xxx_xxxx */ X(cond_jump_n, 0x7100) /* 0111_0001_0xxx_xxxx */ Y(halt, 0x0000) /* 0000_0000_0000_0000 */ #undef X #undef Y