Skip to content

Commit 453eb59

Browse files
lforg37Ferdinand LemaireJessica Paquette
authored andcommitted
[mlir][wasm] Support for variable related instructions in Wasm Importer
--------- Co-authored-by: Ferdinand Lemaire <[email protected]> Co-authored-by: Jessica Paquette <[email protected]>
1 parent 024a7b6 commit 453eb59

File tree

6 files changed

+197
-0
lines changed

6 files changed

+197
-0
lines changed

mlir/include/mlir/Target/Wasm/WasmBinaryEncoding.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ struct WasmBinaryEncoding {
2020
/// Byte encodings for Wasm instructions.
2121
struct OpCode {
2222
// Locals, globals, constants.
23+
static constexpr std::byte localGet{0x20};
24+
static constexpr std::byte localSet{0x21};
25+
static constexpr std::byte localTee{0x22};
26+
static constexpr std::byte globalGet{0x23};
2327
static constexpr std::byte constI32{0x41};
2428
static constexpr std::byte constI64{0x42};
2529
static constexpr std::byte constFP32{0x43};

mlir/lib/Target/Wasm/TranslateFromWasm.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,12 @@ class ExpressionParser {
300300
return valueStack.pushResults(results, &currentOpLoc.value());
301301
}
302302

303+
/// The local.set and local.tee operations behave similarly and only differ
304+
/// on their return value. This function factorizes the behavior of the two
305+
/// operations in one place.
306+
template <typename OpToCreate>
307+
parsed_inst_t parseSetOrTee(OpBuilder &);
308+
303309
private:
304310
std::optional<Location> currentOpLoc;
305311
ParserHead &parser;
@@ -786,6 +792,70 @@ ExpressionParser::parse(OpBuilder &builder,
786792
}
787793
}
788794

795+
template <>
796+
inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
797+
WasmBinaryEncoding::OpCode::localGet>(OpBuilder &builder) {
798+
auto id = parser.parseLiteral<uint32_t>();
799+
auto instLoc = *currentOpLoc;
800+
if (failed(id))
801+
return failure();
802+
if (*id >= locals.size())
803+
return emitError(instLoc, "Invalid local index. Function has ")
804+
<< locals.size() << " accessible locals, received index " << *id;
805+
return {{builder.create<LocalGetOp>(instLoc, locals[*id]).getResult()}};
806+
}
807+
808+
template <>
809+
inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
810+
WasmBinaryEncoding::OpCode::globalGet>(OpBuilder &builder) {
811+
auto id = parser.parseLiteral<uint32_t>();
812+
auto instLoc = *currentOpLoc;
813+
if (failed(id))
814+
return failure();
815+
if (*id >= symbols.globalSymbols.size())
816+
return emitError(instLoc, "Invalid global index. Function has ")
817+
<< symbols.globalSymbols.size()
818+
<< " accessible globals, received index " << *id;
819+
auto globalVar = symbols.globalSymbols[*id];
820+
auto globalOp = builder.create<GlobalGetOp>(instLoc, globalVar.globalType,
821+
globalVar.symbol);
822+
823+
return {{globalOp.getResult()}};
824+
}
825+
826+
template <typename OpToCreate>
827+
parsed_inst_t ExpressionParser::parseSetOrTee(OpBuilder &builder) {
828+
auto id = parser.parseLiteral<uint32_t>();
829+
if (failed(id))
830+
return failure();
831+
if (*id >= locals.size())
832+
return emitError(*currentOpLoc, "Invalid local index. Function has ")
833+
<< locals.size() << " accessible locals, received index " << *id;
834+
if (valueStack.empty())
835+
return emitError(
836+
*currentOpLoc,
837+
"Invalid stack access, trying to access a value on an empty stack.");
838+
839+
parsed_inst_t poppedOp = popOperands(locals[*id].getType().getElementType());
840+
if (failed(poppedOp))
841+
return failure();
842+
return {
843+
builder.create<OpToCreate>(*currentOpLoc, locals[*id], poppedOp->front())
844+
->getResults()};
845+
}
846+
847+
template <>
848+
inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
849+
WasmBinaryEncoding::OpCode::localSet>(OpBuilder &builder) {
850+
return parseSetOrTee<LocalSetOp>(builder);
851+
}
852+
853+
template <>
854+
inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
855+
WasmBinaryEncoding::OpCode::localTee>(OpBuilder &builder) {
856+
return parseSetOrTee<LocalTeeOp>(builder);
857+
}
858+
789859
template <typename T>
790860
inline Type buildLiteralType(OpBuilder &);
791861

mlir/test/Target/Wasm/global.mlir

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,33 @@
1313
(global $normal_glob_i64 i64(i64.const 11))
1414
(global $normal_glob_f32 f32(f32.const 12))
1515
(global $normal_glob_f64 f64(f64.const 13))
16+
17+
(func $main (result i32)
18+
;; load both global variables onto the stack
19+
global.get $imported_glob
20+
global.get $normal_glob
21+
22+
i32.add ;; add up both globals
23+
24+
global.get $glob_mut
25+
global.get $glob_mut_ext
26+
i32.add
27+
i32.add
28+
)
1629
)
1730
*/
1831

1932
// CHECK-LABEL: wasmssa.import_global "from_js" from "env" as @global_0 nested : i32
2033

34+
// CHECK-LABEL: wasmssa.func nested @func_0() -> i32 {
35+
// CHECK: %[[VAL_0:.*]] = wasmssa.global_get @global_0 : i32
36+
// CHECK: %[[VAL_1:.*]] = wasmssa.global_get @global_1 : i32
37+
// CHECK: %[[VAL_2:.*]] = wasmssa.add %[[VAL_0]] %[[VAL_1]] : i32
38+
// CHECK: %[[VAL_3:.*]] = wasmssa.global_get @global_2 : i32
39+
// CHECK: %[[VAL_4:.*]] = wasmssa.global_get @global_3 : i32
40+
// CHECK: %[[VAL_5:.*]] = wasmssa.add %[[VAL_3]] %[[VAL_4]] : i32
41+
// CHECK: %[[VAL_6:.*]] = wasmssa.add %[[VAL_2]] %[[VAL_5]] : i32
42+
// CHECK: wasmssa.return %[[VAL_6]] : i32
2143

2244
// CHECK-LABEL: wasmssa.global @global_1 i32 nested : {
2345
// CHECK: %[[VAL_0:.*]] = wasmssa.const 10 : i32

mlir/test/Target/Wasm/inputs/global.yaml.wasm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,9 @@ Sections:
5555
InitExpr:
5656
Opcode: F64_CONST
5757
Value: 4623507967449235456
58+
- Type: CODE
59+
Functions:
60+
- Index: 0
61+
Locals: []
62+
Body: 230023016A230223036A6A0B
5863
...
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--- !WASM
2+
FileHeader:
3+
Version: 0x1
4+
Sections:
5+
- Type: TYPE
6+
Signatures:
7+
- Index: 0
8+
ParamTypes: []
9+
ReturnTypes:
10+
- F32
11+
- Index: 1
12+
ParamTypes: []
13+
ReturnTypes:
14+
- I32
15+
- Index: 2
16+
ParamTypes:
17+
- I32
18+
ReturnTypes:
19+
- I32
20+
- Type: FUNCTION
21+
FunctionTypes: [ 0, 1, 2 ]
22+
- Type: CODE
23+
Functions:
24+
- Index: 0
25+
Locals:
26+
- Type: F32
27+
Count: 2
28+
Body: 43000000412100200043000040412201920B
29+
- Index: 1
30+
Locals:
31+
- Type: I32
32+
Count: 2
33+
Body: 410821002000410C22016A0B
34+
- Index: 2
35+
Locals: []
36+
Body: 4103210020000B
37+
...

mlir/test/Target/Wasm/local.mlir

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: yaml2obj %S/inputs/local.yaml.wasm -o - | mlir-translate --import-wasm | FileCheck %s
2+
/* Source code used to create this test:
3+
(module
4+
(func $local_f32 (result f32)
5+
(local $var1 f32)
6+
(local $var2 f32)
7+
f32.const 8.0
8+
local.set $var1
9+
local.get $var1
10+
f32.const 12.0
11+
local.tee $var2
12+
f32.add
13+
)
14+
(func $local_i32 (result i32)
15+
(local $var1 i32)
16+
(local $var2 i32)
17+
i32.const 8
18+
local.set $var1
19+
local.get $var1
20+
i32.const 12
21+
local.tee $var2
22+
i32.add
23+
)
24+
(func $local_arg (param $var i32) (result i32)
25+
i32.const 3
26+
local.set $var
27+
local.get $var
28+
)
29+
)
30+
*/
31+
32+
// CHECK-LABEL: wasmssa.func nested @func_0() -> f32 {
33+
// CHECK: %[[VAL_0:.*]] = wasmssa.local of type f32
34+
// CHECK: %[[VAL_1:.*]] = wasmssa.local of type f32
35+
// CHECK: %[[VAL_2:.*]] = wasmssa.const 8.000000e+00 : f32
36+
// CHECK: wasmssa.local_set %[[VAL_0]] : ref to f32 to %[[VAL_2]] : f32
37+
// CHECK: %[[VAL_3:.*]] = wasmssa.local_get %[[VAL_0]] : ref to f32
38+
// CHECK: %[[VAL_4:.*]] = wasmssa.const 1.200000e+01 : f32
39+
// CHECK: %[[VAL_5:.*]] = wasmssa.local_tee %[[VAL_1]] : ref to f32 to %[[VAL_4]] : f32
40+
// CHECK: %[[VAL_6:.*]] = wasmssa.add %[[VAL_3]] %[[VAL_5]] : f32
41+
// CHECK: wasmssa.return %[[VAL_6]] : f32
42+
43+
// CHECK-LABEL: wasmssa.func nested @func_1() -> i32 {
44+
// CHECK: %[[VAL_0:.*]] = wasmssa.local of type i32
45+
// CHECK: %[[VAL_1:.*]] = wasmssa.local of type i32
46+
// CHECK: %[[VAL_2:.*]] = wasmssa.const 8 : i32
47+
// CHECK: wasmssa.local_set %[[VAL_0]] : ref to i32 to %[[VAL_2]] : i32
48+
// CHECK: %[[VAL_3:.*]] = wasmssa.local_get %[[VAL_0]] : ref to i32
49+
// CHECK: %[[VAL_4:.*]] = wasmssa.const 12 : i32
50+
// CHECK: %[[VAL_5:.*]] = wasmssa.local_tee %[[VAL_1]] : ref to i32 to %[[VAL_4]] : i32
51+
// CHECK: %[[VAL_6:.*]] = wasmssa.add %[[VAL_3]] %[[VAL_5]] : i32
52+
// CHECK: wasmssa.return %[[VAL_6]] : i32
53+
54+
// CHECK-LABEL: wasmssa.func nested @func_2(
55+
// CHECK-SAME: %[[ARG0:.*]]: !wasmssa<local ref to i32>) -> i32 {
56+
// CHECK: %[[VAL_0:.*]] = wasmssa.const 3 : i32
57+
// CHECK: wasmssa.local_set %[[ARG0]] : ref to i32 to %[[VAL_0]] : i32
58+
// CHECK: %[[VAL_1:.*]] = wasmssa.local_get %[[ARG0]] : ref to i32
59+
// CHECK: wasmssa.return %[[VAL_1]] : i32

0 commit comments

Comments
 (0)