From f8a1c5069f382aae5f454433f367aa808c4ba8f9 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Tue, 14 Feb 2023 22:08:37 +0530 Subject: [PATCH 1/3] WASM: Support global variables --- src/libasr/codegen/asr_to_wasm.cpp | 21 +++++++++++++++++++-- src/libasr/codegen/wasm_assembler.h | 12 ++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/libasr/codegen/asr_to_wasm.cpp b/src/libasr/codegen/asr_to_wasm.cpp index 603fbf6ee8..1144036fc4 100644 --- a/src/libasr/codegen/asr_to_wasm.cpp +++ b/src/libasr/codegen/asr_to_wasm.cpp @@ -78,6 +78,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { Vec m_import_section; Vec m_func_section; Vec m_memory_section; + Vec m_global_section; Vec m_export_section; Vec m_code_section; Vec m_data_section; @@ -85,6 +86,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { uint32_t no_of_types; uint32_t no_of_functions; uint32_t no_of_memories; + uint32_t no_of_globals; uint32_t no_of_exports; uint32_t no_of_imports; uint32_t no_of_data_segments; @@ -110,6 +112,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { avail_mem_loc = 0; no_of_functions = 0; no_of_memories = 0; + no_of_globals = 0; no_of_exports = 0; no_of_imports = 0; no_of_data_segments = 0; @@ -121,6 +124,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { m_import_section.reserve(m_al, 1024 * 128); m_func_section.reserve(m_al, 1024 * 128); m_memory_section.reserve(m_al, 1024 * 128); + m_global_section.reserve(m_al, 1024 * 128); m_export_section.reserve(m_al, 1024 * 128); m_code_section.reserve(m_al, 1024 * 128); m_data_section.reserve(m_al, 1024 * 128); @@ -129,10 +133,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { void get_wasm(Vec &code) { code.reserve(m_al, 8U /* preamble size */ + 8U /* (section id + section size) */ * - 7U /* number of sections */ + 8U /* number of sections */ + m_type_section.size() + m_import_section.size() + m_func_section.size() + - m_memory_section.size() + + m_memory_section.size() + m_global_section.size() + m_export_section.size() + m_code_section.size() + m_data_section.size()); @@ -144,6 +148,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { wasm::encode_section(code, m_import_section, m_al, 2U, no_of_imports); wasm::encode_section(code, m_func_section, m_al, 3U, no_of_functions); wasm::encode_section(code, m_memory_section, m_al, 5U, no_of_memories); + wasm::encode_section(code, m_global_section, m_al, 6U, no_of_globals); wasm::encode_section(code, m_export_section, m_al, 7U, no_of_exports); wasm::encode_section(code, m_code_section, m_al, 10U, no_of_functions); wasm::encode_section(code, m_data_section, m_al, 11U, @@ -548,6 +553,16 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { no_of_exports++; } + void declare_global_vars() { + { // global variable to hold the available memory location + m_global_section.push_back(m_al, wasm::type::i32); + m_global_section.push_back(m_al, 0x01 /* mutable */); + wasm::emit_i32_const(m_global_section, m_al, 0); + wasm::emit_expr_end(m_global_section, m_al); // end instructions + no_of_globals++; + } + } + void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { // All loose statements must be converted to a function, so the items // must be empty: @@ -564,6 +579,8 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { wasm::emit_export_mem(m_export_section, m_al, "memory", 0 /* mem_idx */); no_of_exports++; + declare_global_vars(); + emit_string(" "); emit_string("\n"); emit_string("-"); diff --git a/src/libasr/codegen/wasm_assembler.h b/src/libasr/codegen/wasm_assembler.h index 58c99e5d2a..d183edd9e7 100644 --- a/src/libasr/codegen/wasm_assembler.h +++ b/src/libasr/codegen/wasm_assembler.h @@ -236,6 +236,18 @@ void emit_set_local(Vec &code, Allocator &al, uint32_t idx) { emit_u32(code, al, idx); } +// function to emit get global variable at given index +void emit_get_global(Vec &code, Allocator &al, uint32_t idx) { + code.push_back(al, 0x23); + emit_u32(code, al, idx); +} + +// function to emit set global variable at given index +void emit_set_global(Vec &code, Allocator &al, uint32_t idx) { + code.push_back(al, 0x24); + emit_u32(code, al, idx); +} + // function to emit call instruction void emit_call(Vec &code, Allocator &al, uint32_t idx) { code.push_back(al, 0x10); From dcc49be9d7500d4ce2b7fc3408dfee9a799cef92 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Tue, 14 Feb 2023 22:09:31 +0530 Subject: [PATCH 2/3] WAT: Support global variables --- src/libasr/codegen/wasm_decoder.h | 18 ++++++++++++++++++ src/libasr/codegen/wasm_to_wat.cpp | 20 ++++++++++++++++++++ src/libasr/codegen/wasm_utils.h | 6 ++++++ 3 files changed, 44 insertions(+) diff --git a/src/libasr/codegen/wasm_decoder.h b/src/libasr/codegen/wasm_decoder.h index e67044bcb3..69afe6854a 100644 --- a/src/libasr/codegen/wasm_decoder.h +++ b/src/libasr/codegen/wasm_decoder.h @@ -60,6 +60,7 @@ class WASMDecoder { Vec imports; Vec type_indices; Vec> memories; + Vec globals; Vec exports; Vec codes; Vec data_segments; @@ -223,6 +224,19 @@ class WASMDecoder { } } + void decode_global_section(uint32_t offset) { + // read global section contents + uint32_t no_of_globals = read_u32(wasm_bytes, offset); + DEBUG("no_of_globals: " + std::to_string(no_of_globals)); + globals.resize(al, no_of_globals); + + for (uint32_t i = 0; i < no_of_globals; i++) { + globals.p[i].type = read_b8(wasm_bytes, offset); + globals.p[i].mut = read_b8(wasm_bytes, offset); + globals.p[i].insts_start_idx = offset; + } + } + void decode_export_section(uint32_t offset) { // read export section contents uint32_t no_of_exports = read_u32(wasm_bytes, offset); @@ -342,6 +356,10 @@ class WASMDecoder { decode_memory_section(index); // exit(0); break; + case 6U: + decode_global_section(index); + // exit(0); + break; case 7U: decode_export_section(index); // exit(0); diff --git a/src/libasr/codegen/wasm_to_wat.cpp b/src/libasr/codegen/wasm_to_wat.cpp index 041391cedc..2f4cdac358 100644 --- a/src/libasr/codegen/wasm_to_wat.cpp +++ b/src/libasr/codegen/wasm_to_wat.cpp @@ -41,6 +41,12 @@ class WATVisitor : public WASMDecoder, void visit_LocalSet(uint32_t localidx) { src += indent + "local.set " + std::to_string(localidx); } + void visit_GlobalGet(uint32_t globalidx) { + src += indent + "global.get " + std::to_string(globalidx); + } + void visit_GlobalSet(uint32_t globalidx) { + src += indent + "global.set " + std::to_string(globalidx); + } void visit_EmtpyBlockType() {} void visit_If() { src += indent + "if"; @@ -335,6 +341,20 @@ class WATVisitor : public WASMDecoder, } } + for (uint32_t i = 0; i < globals.size(); i++) { + std::string global_initialization_insts = ""; + { + this->offset = globals.p[i].insts_start_idx; + this->indent = ""; + this->src = ""; + decode_instructions(); + global_initialization_insts = this->src; + } + result += indent + "(global $" + std::to_string(i); + result += " " + var_type_to_string[globals[i].type]; + result += " (" + global_initialization_insts + "))"; + } + for (uint32_t i = 0; i < type_indices.size(); i++) { uint32_t func_index = type_indices.p[i]; result += indent + "(func $" + std::to_string(func_index); diff --git a/src/libasr/codegen/wasm_utils.h b/src/libasr/codegen/wasm_utils.h index 8b65afe45a..c7e41cf002 100644 --- a/src/libasr/codegen/wasm_utils.h +++ b/src/libasr/codegen/wasm_utils.h @@ -16,6 +16,12 @@ struct FuncType { Vec result_types; }; +struct Global { + uint8_t type; + uint8_t mut; + uint32_t insts_start_idx; +}; + struct Export { std::string name; uint8_t kind; From 34de388c475f3072bb147d6bc0a7559218b71a97 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Tue, 14 Feb 2023 22:39:17 +0530 Subject: [PATCH 3/3] TEST: Update reference test --- tests/reference/wat-bool1-234bcd1.json | 2 +- tests/reference/wat-bool1-234bcd1.stdout | 1 + tests/reference/wat-expr14-5e0cb96.json | 2 +- tests/reference/wat-expr14-5e0cb96.stdout | 1 + tests/reference/wat-expr2-8b17723.json | 2 +- tests/reference/wat-expr2-8b17723.stdout | 1 + tests/reference/wat-expr9-f73afd1.json | 2 +- tests/reference/wat-expr9-f73afd1.stdout | 1 + tests/reference/wat-loop1-e0046d4.json | 2 +- tests/reference/wat-loop1-e0046d4.stdout | 1 + tests/reference/wat-print_str-385e953.json | 2 +- tests/reference/wat-print_str-385e953.stdout | 1 + 12 files changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/reference/wat-bool1-234bcd1.json b/tests/reference/wat-bool1-234bcd1.json index 34ad905e0b..8f09553bb6 100644 --- a/tests/reference/wat-bool1-234bcd1.json +++ b/tests/reference/wat-bool1-234bcd1.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "wat-bool1-234bcd1.stdout", - "stdout_hash": "9d7405a88da887d95c18dc2f71c9b516f8ede0664c9e61033976e5c1", + "stdout_hash": "9509a512bd279e27e1c1a4573a344b98e984e93521cef089eb3bb334", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/wat-bool1-234bcd1.stdout b/tests/reference/wat-bool1-234bcd1.stdout index f01bc64935..5819b7337f 100644 --- a/tests/reference/wat-bool1-234bcd1.stdout +++ b/tests/reference/wat-bool1-234bcd1.stdout @@ -8,6 +8,7 @@ (type (;6;) (func (param) (result))) (import "wasi_snapshot_preview1" "proc_exit" (func (;0;) (type 0))) (import "wasi_snapshot_preview1" "fd_write" (func (;1;) (type 1))) + (global $0 i32 (i32.const 0)) (func $2 (type 2) (param i64) (result) (local i64 i64 i64 i64) local.get 0 diff --git a/tests/reference/wat-expr14-5e0cb96.json b/tests/reference/wat-expr14-5e0cb96.json index a0d03b1e7b..f752110448 100644 --- a/tests/reference/wat-expr14-5e0cb96.json +++ b/tests/reference/wat-expr14-5e0cb96.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "wat-expr14-5e0cb96.stdout", - "stdout_hash": "8dd0860fcf3d6380112b1f3b8011b794ffc386a86628aad179297a53", + "stdout_hash": "96f90f190be31d02b145de3fe293bc74b4a79a3a8aa4c8ebb236a4e9", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/wat-expr14-5e0cb96.stdout b/tests/reference/wat-expr14-5e0cb96.stdout index fd43117bb3..d9a929c963 100644 --- a/tests/reference/wat-expr14-5e0cb96.stdout +++ b/tests/reference/wat-expr14-5e0cb96.stdout @@ -7,6 +7,7 @@ (type (;5;) (func (param) (result))) (import "wasi_snapshot_preview1" "proc_exit" (func (;0;) (type 0))) (import "wasi_snapshot_preview1" "fd_write" (func (;1;) (type 1))) + (global $0 i32 (i32.const 0)) (func $2 (type 2) (param i64) (result) (local i64 i64 i64 i64) local.get 0 diff --git a/tests/reference/wat-expr2-8b17723.json b/tests/reference/wat-expr2-8b17723.json index 9007f71fee..d4dedeb06d 100644 --- a/tests/reference/wat-expr2-8b17723.json +++ b/tests/reference/wat-expr2-8b17723.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "wat-expr2-8b17723.stdout", - "stdout_hash": "b3bd5faae5f1632c099d408d9d18c58cb2cfd4f7be1dec2133ec2b1c", + "stdout_hash": "a38ec604027092a7cd322473580201a022de5e7ea948c3b63a8ab798", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/wat-expr2-8b17723.stdout b/tests/reference/wat-expr2-8b17723.stdout index a3f967d8a0..76ef89ccdd 100644 --- a/tests/reference/wat-expr2-8b17723.stdout +++ b/tests/reference/wat-expr2-8b17723.stdout @@ -7,6 +7,7 @@ (type (;5;) (func (param) (result))) (import "wasi_snapshot_preview1" "proc_exit" (func (;0;) (type 0))) (import "wasi_snapshot_preview1" "fd_write" (func (;1;) (type 1))) + (global $0 i32 (i32.const 0)) (func $2 (type 2) (param i64) (result) (local i64 i64 i64 i64) local.get 0 diff --git a/tests/reference/wat-expr9-f73afd1.json b/tests/reference/wat-expr9-f73afd1.json index d57d710c0b..6718a7b064 100644 --- a/tests/reference/wat-expr9-f73afd1.json +++ b/tests/reference/wat-expr9-f73afd1.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "wat-expr9-f73afd1.stdout", - "stdout_hash": "d1025281003011357a1e1e39c7b2eec7752f209d50805aa5a81d83fd", + "stdout_hash": "d1618163ab287b71613fd75147ae7362a7955ebc6e9f32810b21b824", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/wat-expr9-f73afd1.stdout b/tests/reference/wat-expr9-f73afd1.stdout index 4ae07e71a9..d6abccca65 100644 --- a/tests/reference/wat-expr9-f73afd1.stdout +++ b/tests/reference/wat-expr9-f73afd1.stdout @@ -12,6 +12,7 @@ (type (;10;) (func (param) (result))) (import "wasi_snapshot_preview1" "proc_exit" (func (;0;) (type 0))) (import "wasi_snapshot_preview1" "fd_write" (func (;1;) (type 1))) + (global $0 i32 (i32.const 0)) (func $2 (type 2) (param i64) (result) (local i64 i64 i64 i64) local.get 0 diff --git a/tests/reference/wat-loop1-e0046d4.json b/tests/reference/wat-loop1-e0046d4.json index 7fac18d5c3..7f40501269 100644 --- a/tests/reference/wat-loop1-e0046d4.json +++ b/tests/reference/wat-loop1-e0046d4.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "wat-loop1-e0046d4.stdout", - "stdout_hash": "21c5d32f395a2daee2e25240b5a225f6090d2905440973edef350f44", + "stdout_hash": "07cd13d55836deabb991c7762567db212b10e869075d06a6b34476a2", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/wat-loop1-e0046d4.stdout b/tests/reference/wat-loop1-e0046d4.stdout index 309731727e..99cbf50118 100644 --- a/tests/reference/wat-loop1-e0046d4.stdout +++ b/tests/reference/wat-loop1-e0046d4.stdout @@ -11,6 +11,7 @@ (type (;9;) (func (param) (result))) (import "wasi_snapshot_preview1" "proc_exit" (func (;0;) (type 0))) (import "wasi_snapshot_preview1" "fd_write" (func (;1;) (type 1))) + (global $0 i32 (i32.const 0)) (func $2 (type 2) (param i64) (result) (local i64 i64 i64 i64) local.get 0 diff --git a/tests/reference/wat-print_str-385e953.json b/tests/reference/wat-print_str-385e953.json index fe5d60004f..7ba2987dbf 100644 --- a/tests/reference/wat-print_str-385e953.json +++ b/tests/reference/wat-print_str-385e953.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "wat-print_str-385e953.stdout", - "stdout_hash": "51176be242a4d758284827adeb446b6455b2e7a64f15a73daf493efb", + "stdout_hash": "5c741b7c4d2def2a49b189d20e307eba2c157d714d278fc3cc924d7f", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/wat-print_str-385e953.stdout b/tests/reference/wat-print_str-385e953.stdout index 4fbeb425b8..b626d5d4d7 100644 --- a/tests/reference/wat-print_str-385e953.stdout +++ b/tests/reference/wat-print_str-385e953.stdout @@ -9,6 +9,7 @@ (type (;7;) (func (param) (result))) (import "wasi_snapshot_preview1" "proc_exit" (func (;0;) (type 0))) (import "wasi_snapshot_preview1" "fd_write" (func (;1;) (type 1))) + (global $0 i32 (i32.const 0)) (func $2 (type 2) (param i64) (result) (local i64 i64 i64 i64) local.get 0