Progress on basic WASM code generation
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 11 Jun 2020 16:04:12 +0000 (11:04 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 11 Jun 2020 16:04:12 +0000 (11:04 -0500)
onyx
progs/minimal.onyx
src/onyxparser.c
src/onyxutils.c
src/onyxwasm.c

diff --git a/onyx b/onyx
index 6effde6758ecb7c3e7c9778864efb32b9e3bbddb..1be388ef9e86b7705ff8d8bc501ddb7d0dcf39f9 100755 (executable)
Binary files a/onyx and b/onyx differ
index b03f1a58f37576a694c082ed6f63456da0dd0ddf..1356f4ba2b6b1a68cb52ef06e30935a161c0ece0 100644 (file)
@@ -7,10 +7,12 @@ export foo :: proc (foo i32, bar i32) -> i32 {
        return 10 as i32;
 }
 
-export mul :: proc (a i32, b i32) -> i64 {
+export diff_square :: proc (a i64, b i32) -> i64 {
        // Typechecked
-       c :: a - b;
-       d :: a + b;
+       c := a - (b as i64); // Mutable
+       d :: (a as i32) + b; // Constant
 
-       return (c * d) as i64;
+       { f :: 10 as i32; };
+
+       return (c * (d as i64));
 }
index 02454cef552240ba3133dae4c4b99e8eee26e6bd..c271c0f697014030178d608ca20534656421d2bb 100644 (file)
@@ -433,7 +433,7 @@ static OnyxAstNode* parse_return_statement(OnyxParser* parser) {
                if (expr == NULL || expr == &error_node) {
                        return &error_node;
                } else {
-                       return_node->next = expr;
+                       return_node->left = expr;
                }
        }
 
index e40e0cb12a7b6532abb12539f22b7d4880a7ae0f..aff6aba5f38e09d0d4a3a37cdd59aae23ecd44be 100644 (file)
@@ -62,6 +62,10 @@ void onyx_ast_print(OnyxAstNode* node, i32 indent) {
                        onyx_ast_print((OnyxAstNode *) block->body, indent + 1);
                }
 
+               if (block->next) {
+                       onyx_ast_print(block->next, indent);
+               }
+
                break;
        }
 
index 0fcfa6a03f67b7821353aa2684d0b1a1c0ad0cfb..d19909e5a59b2a7f2b14156e071b7c571fc41850 100644 (file)
@@ -14,6 +14,183 @@ const WasmType WASM_TYPE_FLOAT32 = 'C';
 const WasmType WASM_TYPE_FLOAT64 = 'D';
 #endif
 
+static const char* wi_string(WasmInstructionType wit) {
+       switch (wit) {
+               case WI_UNREACHABLE: return "WI_UNREACHABLE";
+               case WI_NOP: return "WI_NOP";
+               case WI_BLOCK_START: return "WI_BLOCK_START";
+               case WI_BLOCK_END: return "WI_BLOCK_END";
+               case WI_LOOP_START: return "WI_LOOP_START";
+               case WI_IF_START: return "WI_IF_START";
+               case WI_ELSE: return "WI_ELSE";
+               case WI_JUMP: return "WI_JUMP";
+               case WI_COND_JUMP: return "WI_COND_JUMP";
+               case WI_JUMP_TABLE: return "WI_JUMP_TABLE";
+               case WI_RETURN: return "WI_RETURN";
+               case WI_CALL: return "WI_CALL";
+               case WI_CALL_INDIRECT: return "WI_CALL_INDIRECT";
+               case WI_DROP: return "WI_DROP";
+               case WI_SELECT: return "WI_SELECT";
+               case WI_LOCAL_GET: return "WI_LOCAL_GET";
+               case WI_LOCAL_SET: return "WI_LOCAL_SET";
+               case WI_LOCAL_TEE: return "WI_LOCAL_TEE";
+               case WI_GLOBAL_GET: return "WI_GLOBAL_GET";
+               case WI_GLOBAL_SET: return "WI_GLOBAL_SET";
+               case WI_I32_LOAD: return "WI_I32_LOAD";
+               case WI_I64_LOAD: return "WI_I64_LOAD";
+               case WI_F32_LOAD: return "WI_F32_LOAD";
+               case WI_F64_LOAD: return "WI_F64_LOAD";
+               case WI_I32_LOAD_8_S: return "WI_I32_LOAD_8_S";
+               case WI_I32_LOAD_8_U: return "WI_I32_LOAD_8_U";
+               case WI_I32_LOAD_16_S: return "WI_I32_LOAD_16_S";
+               case WI_I32_LOAD_16_U: return "WI_I32_LOAD_16_U";
+               case WI_I64_LOAD_8_S: return "WI_I64_LOAD_8_S";
+               case WI_I64_LOAD_8_U: return "WI_I64_LOAD_8_U";
+               case WI_I64_LOAD_16_S: return "WI_I64_LOAD_16_S";
+               case WI_I64_LOAD_16_U: return "WI_I64_LOAD_16_U";
+               case WI_I64_LOAD_32_S: return "WI_I64_LOAD_32_S";
+               case WI_I64_LOAD_32_U: return "WI_I64_LOAD_32_U";
+               case WI_I32_STORE: return "WI_I32_STORE";
+               case WI_I64_STORE: return "WI_I64_STORE";
+               case WI_F32_STORE: return "WI_F32_STORE";
+               case WI_F64_STORE: return "WI_F64_STORE";
+               case WI_I32_STORE_8: return "WI_I32_STORE_8";
+               case WI_I32_STORE_16: return "WI_I32_STORE_16";
+               case WI_I64_STORE_8: return "WI_I64_STORE_8";
+               case WI_I64_STORE_16: return "WI_I64_STORE_16";
+               case WI_I64_STORE_32: return "WI_I64_STORE_32";
+               case WI_MEMORY_SIZE: return "WI_MEMORY_SIZE";
+               case WI_MEMORY_GROW: return "WI_MEMORY_GROW";
+               case WI_I32_CONST: return "WI_I32_CONST";
+               case WI_I64_CONST: return "WI_I64_CONST";
+               case WI_F32_CONST: return "WI_F32_CONST";
+               case WI_F64_CONST: return "WI_F64_CONST";
+               case WI_I32_EQZ: return "WI_I32_EQZ";
+               case WI_I32_EQ: return "WI_I32_EQ";
+               case WI_I32_NE: return "WI_I32_NE";
+               case WI_I32_LT_S: return "WI_I32_LT_S";
+               case WI_I32_LT_U: return "WI_I32_LT_U";
+               case WI_I32_GT_S: return "WI_I32_GT_S";
+               case WI_I32_GT_U: return "WI_I32_GT_U";
+               case WI_I32_LE_S: return "WI_I32_LE_S";
+               case WI_I32_LE_U: return "WI_I32_LE_U";
+               case WI_I32_GE_S: return "WI_I32_GE_S";
+               case WI_I32_GE_U: return "WI_I32_GE_U";
+               case WI_I64_EQZ: return "WI_I64_EQZ";
+               case WI_I64_EQ: return "WI_I64_EQ";
+               case WI_I64_NE: return "WI_I64_NE";
+               case WI_I64_LT_S: return "WI_I64_LT_S";
+               case WI_I64_LT_U: return "WI_I64_LT_U";
+               case WI_I64_GT_S: return "WI_I64_GT_S";
+               case WI_I64_GT_U: return "WI_I64_GT_U";
+               case WI_I64_LE_S: return "WI_I64_LE_S";
+               case WI_I64_LE_U: return "WI_I64_LE_U";
+               case WI_I64_GE_S: return "WI_I64_GE_S";
+               case WI_I64_GE_U: return "WI_I64_GE_U";
+               case WI_F32_EQ: return "WI_F32_EQ";
+               case WI_F32_NE: return "WI_F32_NE";
+               case WI_F32_LT: return "WI_F32_LT";
+               case WI_F32_GT: return "WI_F32_GT";
+               case WI_F32_LE: return "WI_F32_LE";
+               case WI_F32_GE: return "WI_F32_GE";
+               case WI_F64_EQ: return "WI_F64_EQ";
+               case WI_F64_NE: return "WI_F64_NE";
+               case WI_F64_LT: return "WI_F64_LT";
+               case WI_F64_GT: return "WI_F64_GT";
+               case WI_F64_LE: return "WI_F64_LE";
+               case WI_F64_GE: return "WI_F64_GE";
+               case WI_I32_CLZ: return "WI_I32_CLZ";
+               case WI_I32_CTZ: return "WI_I32_CTZ";
+               case WI_I32_POPCNT: return "WI_I32_POPCNT";
+               case WI_I32_ADD: return "WI_I32_ADD";
+               case WI_I32_SUB: return "WI_I32_SUB";
+               case WI_I32_MUL: return "WI_I32_MUL";
+               case WI_I32_DIV_S: return "WI_I32_DIV_S";
+               case WI_I32_DIV_U: return "WI_I32_DIV_U";
+               case WI_I32_REM_S: return "WI_I32_REM_S";
+               case WI_I32_REM_U: return "WI_I32_REM_U";
+               case WI_I32_AND: return "WI_I32_AND";
+               case WI_I32_OR: return "WI_I32_OR";
+               case WI_I32_XOR: return "WI_I32_XOR";
+               case WI_I32_SHL: return "WI_I32_SHL";
+               case WI_I32_SHR_S: return "WI_I32_SHR_S";
+               case WI_I32_SHR_U: return "WI_I32_SHR_U";
+               case WI_I32_ROTL: return "WI_I32_ROTL";
+               case WI_I32_ROTR: return "WI_I32_ROTR";
+               case WI_I64_CLZ: return "WI_I64_CLZ";
+               case WI_I64_CTZ: return "WI_I64_CTZ";
+               case WI_I64_POPCNT: return "WI_I64_POPCNT";
+               case WI_I64_ADD: return "WI_I64_ADD";
+               case WI_I64_SUB: return "WI_I64_SUB";
+               case WI_I64_MUL: return "WI_I64_MUL";
+               case WI_I64_DIV_S: return "WI_I64_DIV_S";
+               case WI_I64_DIV_U: return "WI_I64_DIV_U";
+               case WI_I64_REM_S: return "WI_I64_REM_S";
+               case WI_I64_REM_U: return "WI_I64_REM_U";
+               case WI_I64_AND: return "WI_I64_AND";
+               case WI_I64_OR: return "WI_I64_OR";
+               case WI_I64_XOR: return "WI_I64_XOR";
+               case WI_I64_SHL: return "WI_I64_SHL";
+               case WI_I64_SHR_S: return "WI_I64_SHR_S";
+               case WI_I64_SHR_U: return "WI_I64_SHR_U";
+               case WI_I64_ROTL: return "WI_I64_ROTL";
+               case WI_I64_ROTR: return "WI_I64_ROTR";
+               case WI_F32_ABS: return "WI_F32_ABS";
+               case WI_F32_NEG: return "WI_F32_NEG";
+               case WI_F32_CEIL: return "WI_F32_CEIL";
+               case WI_F32_FLOOR: return "WI_F32_FLOOR";
+               case WI_F32_TRUNC: return "WI_F32_TRUNC";
+               case WI_F32_NEAREST: return "WI_F32_NEAREST";
+               case WI_F32_SQRT: return "WI_F32_SQRT";
+               case WI_F32_ADD: return "WI_F32_ADD";
+               case WI_F32_SUB: return "WI_F32_SUB";
+               case WI_F32_MUL: return "WI_F32_MUL";
+               case WI_F32_DIV: return "WI_F32_DIV";
+               case WI_F32_MIN: return "WI_F32_MIN";
+               case WI_F32_MAX: return "WI_F32_MAX";
+               case WI_F32_COPYSIGN: return "WI_F32_COPYSIGN";
+               case WI_F64_ABS: return "WI_F64_ABS";
+               case WI_F64_NEG: return "WI_F64_NEG";
+               case WI_F64_CEIL: return "WI_F64_CEIL";
+               case WI_F64_FLOOR: return "WI_F64_FLOOR";
+               case WI_F64_TRUNC: return "WI_F64_TRUNC";
+               case WI_F64_NEAREST: return "WI_F64_NEAREST";
+               case WI_F64_SQRT: return "WI_F64_SQRT";
+               case WI_F64_ADD: return "WI_F64_ADD";
+               case WI_F64_SUB: return "WI_F64_SUB";
+               case WI_F64_MUL: return "WI_F64_MUL";
+               case WI_F64_DIV: return "WI_F64_DIV";
+               case WI_F64_MIN: return "WI_F64_MIN";
+               case WI_F64_MAX: return "WI_F64_MAX";
+               case WI_F64_COPYSIGN: return "WI_F64_COPYSIGN";
+               case WI_I32_FROM_I64: return "WI_I32_FROM_I64";
+               case WI_I32_FROM_F32_S: return "WI_I32_FROM_F32_S";
+               case WI_I32_FROM_F32_U: return "WI_I32_FROM_F32_U";
+               case WI_I32_FROM_F64_S: return "WI_I32_FROM_F64_S";
+               case WI_I32_FROM_F64_U: return "WI_I32_FROM_F64_U";
+               case WI_I64_FROM_I32_S: return "WI_I64_FROM_I32_S";
+               case WI_I64_FROM_I32_U: return "WI_I64_FROM_I32_U";
+               case WI_I64_FROM_F32_S: return "WI_I64_FROM_F32_S";
+               case WI_I64_FROM_F32_U: return "WI_I64_FROM_F32_U";
+               case WI_I64_FROM_F64_S: return "WI_I64_FROM_F64_S";
+               case WI_I64_FROM_F64_U: return "WI_I64_FROM_F64_U";
+               case WI_F32_FROM_I32_S: return "WI_F32_FROM_I32_S";
+               case WI_F32_FROM_I32_U: return "WI_F32_FROM_I32_U";
+               case WI_F32_FROM_I64_S: return "WI_F32_FROM_I64_S";
+               case WI_F32_FROM_I64_U: return "WI_F32_FROM_I64_U";
+               case WI_F32_FROM_F64: return "WI_F32_FROM_F64";
+               case WI_F64_FROM_I32_S: return "WI_F64_FROM_I32_S";
+               case WI_F64_FROM_I32_U: return "WI_F64_FROM_I32_U";
+               case WI_F64_FROM_I64_S: return "WI_F64_FROM_I64_S";
+               case WI_F64_FROM_I64_U: return "WI_F64_FROM_I64_U";
+               case WI_F64_FROM_F32: return "WI_F64_FROM_F32";
+               case WI_I32_REINTERPRET_F32: return "WI_I32_REINTERPRET_F32";
+               case WI_I64_REINTERPRET_F64: return "WI_I64_REINTERPRET_F64";
+               case WI_F32_REINTERPRET_I32: return "WI_F32_REINTERPRET_I32";
+               case WI_F64_REINTERPRET_I64: return "WI_F64_REINTERPRET_I64";
+       }
+}
+
 static WasmType onyx_type_to_wasm_type(OnyxTypeInfo* type) {
        if (type->is_bool) return WASM_TYPE_INT32;
        else if (type->is_int) {
@@ -29,6 +206,202 @@ static WasmType onyx_type_to_wasm_type(OnyxTypeInfo* type) {
        return WASM_TYPE_INT32;
 }
 
+static void process_block(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeBlock* block, b32 top_level);
+static void process_statement(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* stmt);
+static void process_assign_lval(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* lval);
+static void process_assignment(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* assign);
+static void process_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* expr);
+static void process_cast(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* cast);
+static void process_return(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* ret);
+
+static void process_block(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeBlock* block, b32 top_level) {
+       if (!top_level) {
+               bh_arr_push(func->code, ((WasmInstruction){ WI_BLOCK_START, 0x40 }));
+       }
+
+       forll (OnyxAstNode, stmt, block->body, next) {
+               process_statement(mod, func, stmt);
+       }
+
+       if (!top_level) {
+               bh_arr_push(func->code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));
+       }
+}
+
+static void process_statement(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* stmt) {
+       switch (stmt->kind) {
+               case ONYX_AST_NODE_KIND_SCOPE: break;
+               case ONYX_AST_NODE_KIND_RETURN: process_return(mod, func, stmt); break;
+               case ONYX_AST_NODE_KIND_ASSIGNMENT: process_assignment(mod, func, stmt); break;
+               default: process_expression(mod, func, stmt);
+       }
+}
+
+static void process_assign_lval(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* lval) {
+       if (lval->kind == ONYX_AST_NODE_KIND_LOCAL || lval->kind == ONYX_AST_NODE_KIND_PARAM) {
+               onyx_token_null_toggle(*lval->token);
+               i32 localidx = bh_hash_get(i32, mod->local_map, lval->token->token);
+               onyx_token_null_toggle(*lval->token);
+
+               bh_arr_push(func->code, ((WasmInstruction){ WI_LOCAL_SET, localidx }));
+       } else {
+               assert(("Invalid lval", 0));
+       }
+}
+
+static void process_assignment(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* assign) {
+       process_expression(mod, func, assign->right);
+       process_assign_lval(mod, func, assign->left);
+}
+
+#define BIN_OP_PROCESS(ast_binop, wasm_binop) \
+       case ONYX_AST_NODE_KIND_##ast_binop: \
+               { \
+                       WasmInstructionType instr_type; \
+                       switch (expr->type->kind) { \
+                               case ONYX_TYPE_INFO_KIND_INT32: instr_type = WI_I32_##wasm_binop;               break; \
+                               case ONYX_TYPE_INFO_KIND_INT64: instr_type = WI_I64_##wasm_binop;               break; \
+                               case ONYX_TYPE_INFO_KIND_FLOAT32: instr_type = WI_F32_##wasm_binop;             break; \
+                               case ONYX_TYPE_INFO_KIND_FLOAT64: instr_type = WI_F64_##wasm_binop;             break; \
+                               default: assert(("Invalid type", 0)); \
+                       } \
+ \
+                       process_expression(mod, func, expr->left); \
+                       process_expression(mod, func, expr->right); \
+                       bh_arr_push(func->code, ((WasmInstruction){ instr_type, 0x00 })); \
+                       break; \
+               }
+
+static void process_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* expr) {
+       switch (expr->kind) {
+               BIN_OP_PROCESS(ADD, ADD);
+               BIN_OP_PROCESS(MINUS, SUB);
+               BIN_OP_PROCESS(MULTIPLY, MUL);
+
+               case ONYX_AST_NODE_KIND_DIVIDE:
+                       {
+                               WasmInstructionType instr_type;
+                               switch (expr->type->kind) {
+                                       case ONYX_TYPE_INFO_KIND_INT32:
+                                               if (expr->type->is_unsigned) instr_type = WI_I32_DIV_U;
+                                               else instr_type = WI_I32_DIV_S;
+                                               break;
+                                       case ONYX_TYPE_INFO_KIND_INT64:
+                                               if (expr->type->is_unsigned) instr_type = WI_I64_DIV_U;
+                                               else instr_type = WI_I64_DIV_S;
+                                               break;
+                                       case ONYX_TYPE_INFO_KIND_FLOAT32: instr_type = WI_F32_DIV;              break;
+                                       case ONYX_TYPE_INFO_KIND_FLOAT64: instr_type = WI_F64_DIV;              break;
+                                       default: assert(("Invalid type", 0));
+                               }
+
+                               process_expression(mod, func, expr->left);
+                               process_expression(mod, func, expr->right);
+                               bh_arr_push(func->code, ((WasmInstruction){ instr_type, 0x00 }));
+                               break;
+                       }
+
+               case ONYX_AST_NODE_KIND_MODULUS:
+                       {
+                               WasmInstructionType instr_type;
+                               switch (expr->type->kind) {
+                                       case ONYX_TYPE_INFO_KIND_INT32:
+                                               if (expr->type->is_unsigned) instr_type = WI_I32_REM_U;
+                                               else instr_type = WI_I32_REM_S;
+                                               break;
+                                       case ONYX_TYPE_INFO_KIND_INT64:
+                                               if (expr->type->is_unsigned) instr_type = WI_I64_REM_U;
+                                               else instr_type = WI_I64_REM_S;
+                                               break;
+                                       default: assert(("Invalid type", 0));
+                               }
+
+                               process_expression(mod, func, expr->left);
+                               process_expression(mod, func, expr->right);
+                               bh_arr_push(func->code, ((WasmInstruction){ instr_type, 0x00 }));
+                               break;
+                       }
+
+               case ONYX_AST_NODE_KIND_LOCAL:
+               case ONYX_AST_NODE_KIND_PARAM:
+                       {
+                               onyx_token_null_toggle(*expr->token);
+                               i32 localidx = bh_hash_get(i32, mod->local_map, expr->token->token);
+                               onyx_token_null_toggle(*expr->token);
+
+                               bh_arr_push(func->code, ((WasmInstruction){ WI_LOCAL_GET, localidx }));
+                               break;
+                       }
+
+               case ONYX_AST_NODE_KIND_CAST: process_cast(mod, func, expr); break;
+               case ONYX_AST_NODE_KIND_LITERAL:
+                       {
+                               // TODO: Implement proper literal type detection and parsing
+                               i64 value = 0;
+
+                               bh_arr_push(func->code, ((WasmInstruction){ WI_I64_CONST, value }));
+                               break;
+                       }
+
+               case ONYX_AST_NODE_KIND_BLOCK: process_block(mod, func, (OnyxAstNodeBlock *) expr, 0); break;
+
+               default:
+                       bh_printf("Unhandled case: %d\n", expr->kind);
+                       assert(0);
+       }
+}
+
+static const WasmInstructionType cast_map[][6] = {
+       //                      I32                                     U32                                     I64                                     U64                                     F32                                     F64
+       /* I32 */ {     WI_NOP,                         WI_NOP,                         WI_I64_FROM_I32_S,      WI_I64_FROM_I32_S,      WI_F32_FROM_I32_S,      WI_F64_FROM_I32_S },
+       /* U32 */ {     WI_NOP,                         WI_NOP,                         WI_I64_FROM_I32_U,      WI_I64_FROM_I32_U,      WI_F32_FROM_I32_U,      WI_F64_FROM_I32_U },
+       /* I64 */ { WI_I32_FROM_I64,    WI_I32_FROM_I64,        WI_NOP,                         WI_NOP,                         WI_F32_FROM_I64_S,      WI_F64_FROM_I64_S },
+       /* U64 */ { WI_I32_FROM_I64,    WI_I32_FROM_I64,        WI_NOP,                         WI_NOP,                         WI_F32_FROM_I64_U,      WI_F64_FROM_I64_U },
+       /* F32 */ { WI_I32_FROM_F32_S,  WI_I32_FROM_F32_U,      WI_I64_FROM_F32_S,      WI_I64_FROM_F32_U,      WI_NOP,                         WI_F64_FROM_F32   },
+       /* F64 */ { WI_I32_FROM_F64_S,  WI_I32_FROM_F64_U,      WI_I64_FROM_F64_S,      WI_I64_FROM_F64_U,      WI_F32_FROM_F64,        WI_NOP,                   },
+};
+
+static void process_cast(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* cast) {
+       process_expression(mod, func, cast->left);
+
+       OnyxTypeInfo* from = cast->left->type;
+       OnyxTypeInfo* to = cast->type;
+
+       i32 fromidx = 0, toidx = 0;
+       if (from->is_int) {
+               if (from->size == 4 && !from->is_unsigned) fromidx = 0;
+               else if (from->size == 4 && from->is_unsigned) fromidx = 1;
+               else if (from->size == 8 && !from->is_unsigned) fromidx = 2;
+               else if (from->size == 8 && from->is_unsigned) fromidx = 3;
+       } else if (from->is_float) {
+               if (from->size == 4) fromidx = 4;
+               else if (from->size == 8) fromidx = 5;
+       }
+
+       if (to->is_int) {
+               if (to->size == 4 && !to->is_unsigned) toidx = 0;
+               else if (to->size == 4 && to->is_unsigned) toidx = 1;
+               else if (to->size == 8 && !to->is_unsigned) toidx = 2;
+               else if (to->size == 8 && to->is_unsigned) toidx = 3;
+       } else if (to->is_float) {
+               if (to->size == 4) toidx = 4;
+               else if (to->size == 8) toidx = 5;
+       }
+
+       WasmInstructionType cast_op = cast_map[fromidx][toidx];
+       if (cast_op != WI_NOP) {
+               bh_arr_push(func->code, ((WasmInstruction){ cast_op, 0x00 }));
+       }
+}
+
+static void process_return(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* ret) {
+       if (ret->left) {
+               process_expression(mod, func, ret->left);
+       }
+
+       bh_arr_push(func->code, ((WasmInstruction){ WI_RETURN, 0x00 }));
+}
+
 static void process_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef* fd) {
        static char type_repr_buf[128];
 
@@ -110,6 +483,12 @@ static void process_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef*
        bh_hash_each_end;
 
        // Generate code
+       process_block(mod, &wasm_func, fd->body, 1);
+
+       bh_printf("Code for function:\n");
+       bh_arr_each(WasmInstruction, instr, wasm_func.code) {
+               bh_printf("\t%s\t%xd\n", wi_string(instr->type), instr->data.i1);
+       }
 
        // NOTE: Clear the local map on exit of generating this function
        bh_hash_clear(mod->local_map);