Skip to content

Commit e40f215

Browse files
lforg37Ferdinand LemaireJessica PaquetteLuc Forget
authored
[MLIR][WASM] Control flow, conversion and comparison in Wasm importer (#154674)
This is the following of PR #154452. It extend Wasm binary to Wasm SSA importer with support of control flow operations, comparison operations and conversion operations. --------- Co-authored-by: Ferdinand Lemaire <[email protected]> Co-authored-by: Jessica Paquette <[email protected]> Co-authored-by: Luc Forget <[email protected]>
1 parent 993e80d commit e40f215

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+2633
-263
lines changed

mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td

Lines changed: 122 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,41 @@ class WasmSSA_BlockLikeOp<string mnemonic, string summaryStr> :
4343
let assemblyFormat = "(`(`$inputs^`)` `:` type($inputs))? attr-dict `:` $body `>` $target";
4444
}
4545

46-
def WasmSSA_BlockOp : WasmSSA_BlockLikeOp<"block", "Create a nesting level"> {}
46+
def WasmSSA_BlockOp : WasmSSA_BlockLikeOp<
47+
"block",
48+
"Create a nesting level with a label at its exit."> {
49+
let description = [{
50+
Defines a Wasm block, creating a new nested scope.
51+
A block contains a body region and an optional list of input values.
52+
Control can enter the block and later branch out to the block target.
53+
Example:
54+
55+
```mlir
56+
57+
wasmssa.block {
58+
59+
// instructions
60+
61+
} > ^successor
62+
}];
63+
}
64+
65+
def WasmSSA_LoopOp : WasmSSA_BlockLikeOp<
66+
"loop",
67+
"Create a nesting level that define its entry as jump target."> {
68+
let description = [{
69+
Represents a Wasm loop construct. This defines a nesting level with
70+
a label at the entry of the region.
4771

48-
def WasmSSA_LoopOp : WasmSSA_BlockLikeOp<"loop", "Create a nesting level similar to Block Op, except that it has itself as a successor."> {}
72+
Example:
73+
74+
```mlir
75+
76+
wasmssa.loop {
77+
78+
} > ^successor
79+
}];
80+
}
4981

5082
def WasmSSA_BlockReturnOp : WasmSSA_Op<"block_return", [Terminator,
5183
DeclareOpInterfaceMethods<LabelBranchingOpInterface>]> {
@@ -55,9 +87,16 @@ def WasmSSA_BlockReturnOp : WasmSSA_Op<"block_return", [Terminator,
5587
::mlir::Block* getTarget();
5688
}];
5789
let description = [{
58-
Marks a return from the current block.
90+
Escape from the current nesting level and return the control flow to its successor.
91+
Optionally, mark the arguments that should be transfered to the successor block.
5992

60-
Example:
93+
This shouldn't be confused with branch operations that targets the label defined
94+
by the nesting level operation.
95+
96+
For instance, a `wasmssa.block_return` in a loop will give back control to the
97+
successor of the loop, where a `branch` targeting the loop will flow back to the entry block of the loop.
98+
99+
Example:
61100

62101
```mlir
63102
wasmssa.block_return
@@ -127,12 +166,18 @@ def WasmSSA_FuncOp : WasmSSA_Op<"func", [
127166
- Arguments of the entry block of type `!wasm<local T>`, with T the corresponding type
128167
in the function type.
129168

169+
By default, `wasmssa.func` have nested visibility. Functions exported by the module
170+
are marked with the exported attribute. This gives them public visibility.
171+
130172
Example:
131173

132174
```mlir
133-
// A simple function with no arguments that returns a float32
175+
// Internal function with no arguments that returns a float32
134176
wasmssa.func @my_f32_func() -> f32
135177

178+
// Exported function with no arguments that returns a float32
179+
wasmssa.func exported @my_f32_func() -> f32
180+
136181
// A function that takes a local ref argument
137182
wasmssa.func @i64_wrap(%a: !wasmssa<local ref to i64>) -> i32
138183
```
@@ -141,7 +186,7 @@ def WasmSSA_FuncOp : WasmSSA_Op<"func", [
141186
WasmSSA_FuncTypeAttr: $functionType,
142187
OptionalAttr<DictArrayAttr>:$arg_attrs,
143188
OptionalAttr<DictArrayAttr>:$res_attrs,
144-
DefaultValuedAttr<StrAttr, "\"nested\"">:$sym_visibility);
189+
UnitAttr: $exported);
145190
let regions = (region AnyRegion: $body);
146191
let extraClassDeclaration = [{
147192

@@ -162,6 +207,12 @@ def WasmSSA_FuncOp : WasmSSA_Op<"func", [
162207

163208
/// Returns the result types of this function.
164209
ArrayRef<Type> getResultTypes() { return getFunctionType().getResults(); }
210+
211+
::mlir::SymbolTable::Visibility getVisibility() {
212+
return getExported() ?
213+
::mlir::SymbolTable::Visibility::Public :
214+
::mlir::SymbolTable::Visibility::Nested;
215+
};
165216
}];
166217

167218
let builders = [
@@ -207,8 +258,7 @@ def WasmSSA_FuncImportOp : WasmSSA_Op<"import_func", [
207258
StrAttr: $importName,
208259
WasmSSA_FuncTypeAttr: $type,
209260
OptionalAttr<DictArrayAttr>:$arg_attrs,
210-
OptionalAttr<DictArrayAttr>:$res_attrs,
211-
OptionalAttr<StrAttr>:$sym_visibility);
261+
OptionalAttr<DictArrayAttr>:$res_attrs);
212262
let extraClassDeclaration = [{
213263
bool isDeclaration() const { return true; }
214264

@@ -221,6 +271,10 @@ def WasmSSA_FuncImportOp : WasmSSA_Op<"import_func", [
221271
::llvm::ArrayRef<Type> getResultTypes() {
222272
return getType().getResults();
223273
}
274+
275+
::mlir::SymbolTable::Visibility getVisibility() {
276+
return ::mlir::SymbolTable::Visibility::Nested;
277+
};
224278
}];
225279
let builders = [
226280
OpBuilder<(ins "StringRef":$symbol,
@@ -238,30 +292,41 @@ def WasmSSA_GlobalOp : WasmSSA_Op<"global", [
238292
let arguments = (ins SymbolNameAttr: $sym_name,
239293
WasmSSA_ValTypeAttr: $type,
240294
UnitAttr: $isMutable,
241-
OptionalAttr<StrAttr>:$sym_visibility);
295+
UnitAttr: $exported);
242296
let description = [{
243297
WebAssembly global variable.
244298
Body contains the initialization instructions for the variable value.
245299
The body must contain only instructions considered `const` in a webassembly context,
246300
such as `wasmssa.const` or `global.get`.
247301

302+
By default, `wasmssa.global` have nested visibility. Global exported by the module
303+
are marked with the exported attribute. This gives them public visibility.
304+
248305
Example:
249306

250307
```mlir
251-
// Define a global_var, a mutable i32 global variable equal to 10.
252-
wasmssa.global @global_var i32 mutable nested : {
308+
// Define module_global_var, an internal mutable i32 global variable equal to 10.
309+
wasmssa.global @module_global_var i32 mutable : {
253310
%[[VAL_0:.*]] = wasmssa.const 10 : i32
254311
wasmssa.return %[[VAL_0]] : i32
255312
}
313+
314+
// Define global_var, an exported constant i32 global variable equal to 42.
315+
wasmssa.global @global_var i32 : {
316+
%[[VAL_0:.*]] = wasmssa.const 42 : i32
317+
wasmssa.return %[[VAL_0]] : i32
318+
}
256319
```
257320
}];
258321
let regions = (region AnyRegion: $initializer);
259322

260-
let builders = [
261-
OpBuilder<(ins "StringRef":$symbol,
262-
"Type": $type,
263-
"bool": $isMutable)>
264-
];
323+
let extraClassDeclaration = [{
324+
::mlir::SymbolTable::Visibility getVisibility() {
325+
return getExported() ?
326+
::mlir::SymbolTable::Visibility::Public :
327+
::mlir::SymbolTable::Visibility::Nested;
328+
};
329+
}];
265330
let hasCustomAssemblyFormat = 1;
266331
}
267332

@@ -283,18 +348,14 @@ def WasmSSA_GlobalImportOp : WasmSSA_Op<"import_global", [
283348
StrAttr: $moduleName,
284349
StrAttr: $importName,
285350
WasmSSA_ValTypeAttr: $type,
286-
UnitAttr: $isMutable,
287-
OptionalAttr<StrAttr>:$sym_visibility);
351+
UnitAttr: $isMutable);
288352
let extraClassDeclaration = [{
289353
bool isDeclaration() const { return true; }
354+
355+
::mlir::SymbolTable::Visibility getVisibility() {
356+
return ::mlir::SymbolTable::Visibility::Nested;
357+
};
290358
}];
291-
let builders = [
292-
OpBuilder<(ins "StringRef":$symbol,
293-
"StringRef":$moduleName,
294-
"StringRef":$importName,
295-
"Type": $type,
296-
"bool": $isMutable)>
297-
];
298359
let hasCustomAssemblyFormat = 1;
299360
}
300361

@@ -442,23 +503,33 @@ def WasmSSA_MemOp : WasmSSA_Op<"memory", [Symbol]> {
442503
Define a memory to be used by the program.
443504
Multiple memories can be defined in the same module.
444505

506+
By default, `wasmssa.memory` have nested visibility. Memory exported by
507+
the module are marked with the exported attribute. This gives them public
508+
visibility.
509+
445510
Example:
446511

447512
```mlir
448-
// Define the `mem_0` memory with defined bounds of 0 -> 65536
513+
// Define the `mem_0` (internal) memory with defined size bounds of [0:65536]
449514
wasmssa.memory @mem_0 !wasmssa<limit[0:65536]>
515+
516+
// Define the `mem_1` exported memory with minimal size of 512
517+
wasmssa.memory exported @mem_1 !wasmssa<limit[512:]>
450518
```
451519
}];
452520
let arguments = (ins SymbolNameAttr: $sym_name,
453521
WasmSSA_LimitTypeAttr: $limits,
454-
OptionalAttr<StrAttr>:$sym_visibility);
455-
let builders = [
456-
OpBuilder<(ins
457-
"::llvm::StringRef":$symbol,
458-
"wasmssa::LimitType":$limit)>
459-
];
522+
UnitAttr: $exported);
460523

461-
let assemblyFormat = "$sym_name custom<WasmVisibility>($sym_visibility) $limits attr-dict";
524+
let extraClassDeclaration = [{
525+
::mlir::SymbolTable::Visibility getVisibility() {
526+
return getExported() ?
527+
::mlir::SymbolTable::Visibility::Public :
528+
::mlir::SymbolTable::Visibility::Nested;
529+
};
530+
}];
531+
532+
let assemblyFormat = "(`exported` $exported^)? $sym_name $limits attr-dict";
462533
}
463534

464535
def WasmSSA_MemImportOp : WasmSSA_Op<"import_mem", [Symbol, ImportOpInterface]> {
@@ -476,28 +547,29 @@ def WasmSSA_MemImportOp : WasmSSA_Op<"import_mem", [Symbol, ImportOpInterface]>
476547
let arguments = (ins SymbolNameAttr: $sym_name,
477548
StrAttr: $moduleName,
478549
StrAttr: $importName,
479-
WasmSSA_LimitTypeAttr: $limits,
480-
OptionalAttr<StrAttr>:$sym_visibility);
550+
WasmSSA_LimitTypeAttr: $limits);
481551
let extraClassDeclaration = [{
482-
bool isDeclaration() const { return true; }
552+
bool isDeclaration() const { return true; }
553+
::mlir::SymbolTable::Visibility getVisibility() {
554+
return ::mlir::SymbolTable::Visibility::Nested;
555+
};
483556
}];
484-
let builders = [OpBuilder<(ins
485-
"::llvm::StringRef":$symbol,
486-
"::llvm::StringRef":$moduleName,
487-
"::llvm::StringRef":$importName,
488-
"wasmssa::LimitType":$limits)>];
489557
let assemblyFormat = "$importName `from` $moduleName `as` $sym_name attr-dict";
490558
}
491559

492560
def WasmSSA_TableOp : WasmSSA_Op<"table", [Symbol]> {
493561
let summary= "WebAssembly table value";
494562
let arguments = (ins SymbolNameAttr: $sym_name,
495563
WasmSSA_TableTypeAttr: $type,
496-
OptionalAttr<StrAttr>:$sym_visibility);
497-
let builders = [OpBuilder<(ins
498-
"::llvm::StringRef":$symbol,
499-
"wasmssa::TableType":$type)>];
500-
let assemblyFormat = "$sym_name custom<WasmVisibility>($sym_visibility) $type attr-dict";
564+
UnitAttr: $exported);
565+
let extraClassDeclaration = [{
566+
::mlir::SymbolTable::Visibility getVisibility() {
567+
return getExported() ?
568+
::mlir::SymbolTable::Visibility::Public :
569+
::mlir::SymbolTable::Visibility::Nested;
570+
};
571+
}];
572+
let assemblyFormat = "(`exported` $exported^)? $sym_name $type attr-dict";
501573
}
502574

503575
def WasmSSA_TableImportOp : WasmSSA_Op<"import_table", [Symbol, ImportOpInterface]> {
@@ -515,17 +587,14 @@ def WasmSSA_TableImportOp : WasmSSA_Op<"import_table", [Symbol, ImportOpInterfac
515587
let arguments = (ins SymbolNameAttr: $sym_name,
516588
StrAttr: $moduleName,
517589
StrAttr: $importName,
518-
WasmSSA_TableTypeAttr: $type,
519-
OptionalAttr<StrAttr>:$sym_visibility);
590+
WasmSSA_TableTypeAttr: $type);
520591
let extraClassDeclaration = [{
521592
bool isDeclaration() const { return true; }
593+
::mlir::SymbolTable::Visibility getVisibility() {
594+
return ::mlir::SymbolTable::Visibility::Nested;
595+
};
522596
}];
523597
let assemblyFormat = "$importName `from` $moduleName `as` $sym_name attr-dict";
524-
let builders = [OpBuilder<(ins
525-
"::llvm::StringRef":$symbol,
526-
"::llvm::StringRef":$moduleName,
527-
"::llvm::StringRef":$importName,
528-
"wasmssa::TableType":$type)>];
529598
}
530599

531600
def WasmSSA_ReturnOp : WasmSSA_Op<"return", [Terminator]> {

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

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ namespace mlir {
1919
struct WasmBinaryEncoding {
2020
/// Byte encodings for Wasm instructions.
2121
struct OpCode {
22+
// Control instructions.
23+
static constexpr std::byte block{0x02};
24+
static constexpr std::byte loop{0x03};
25+
static constexpr std::byte ifOpCode{0x04};
26+
static constexpr std::byte elseOpCode{0x05};
27+
static constexpr std::byte branchIf{0x0D};
28+
static constexpr std::byte call{0x10};
29+
2230
// Locals, globals, constants.
2331
static constexpr std::byte localGet{0x20};
2432
static constexpr std::byte localSet{0x21};
@@ -29,6 +37,42 @@ struct WasmBinaryEncoding {
2937
static constexpr std::byte constFP32{0x43};
3038
static constexpr std::byte constFP64{0x44};
3139

40+
// Comparisons.
41+
static constexpr std::byte eqzI32{0x45};
42+
static constexpr std::byte eqI32{0x46};
43+
static constexpr std::byte neI32{0x47};
44+
static constexpr std::byte ltSI32{0x48};
45+
static constexpr std::byte ltUI32{0x49};
46+
static constexpr std::byte gtSI32{0x4A};
47+
static constexpr std::byte gtUI32{0x4B};
48+
static constexpr std::byte leSI32{0x4C};
49+
static constexpr std::byte leUI32{0x4D};
50+
static constexpr std::byte geSI32{0x4E};
51+
static constexpr std::byte geUI32{0x4F};
52+
static constexpr std::byte eqzI64{0x50};
53+
static constexpr std::byte eqI64{0x51};
54+
static constexpr std::byte neI64{0x52};
55+
static constexpr std::byte ltSI64{0x53};
56+
static constexpr std::byte ltUI64{0x54};
57+
static constexpr std::byte gtSI64{0x55};
58+
static constexpr std::byte gtUI64{0x56};
59+
static constexpr std::byte leSI64{0x57};
60+
static constexpr std::byte leUI64{0x58};
61+
static constexpr std::byte geSI64{0x59};
62+
static constexpr std::byte geUI64{0x5A};
63+
static constexpr std::byte eqF32{0x5B};
64+
static constexpr std::byte neF32{0x5C};
65+
static constexpr std::byte ltF32{0x5D};
66+
static constexpr std::byte gtF32{0x5E};
67+
static constexpr std::byte leF32{0x5F};
68+
static constexpr std::byte geF32{0x60};
69+
static constexpr std::byte eqF64{0x61};
70+
static constexpr std::byte neF64{0x62};
71+
static constexpr std::byte ltF64{0x63};
72+
static constexpr std::byte gtF64{0x64};
73+
static constexpr std::byte leF64{0x65};
74+
static constexpr std::byte geF64{0x66};
75+
3276
// Numeric operations.
3377
static constexpr std::byte clzI32{0x67};
3478
static constexpr std::byte ctzI32{0x68};
@@ -93,6 +137,33 @@ struct WasmBinaryEncoding {
93137
static constexpr std::byte maxF64{0xA5};
94138
static constexpr std::byte copysignF64{0xA6};
95139
static constexpr std::byte wrap{0xA7};
140+
141+
// Conversion operations
142+
static constexpr std::byte extendS{0xAC};
143+
static constexpr std::byte extendU{0xAD};
144+
static constexpr std::byte convertSI32F32{0xB2};
145+
static constexpr std::byte convertUI32F32{0xB3};
146+
static constexpr std::byte convertSI64F32{0xB4};
147+
static constexpr std::byte convertUI64F32{0xB5};
148+
149+
static constexpr std::byte demoteF64ToF32{0xB6};
150+
151+
static constexpr std::byte convertSI32F64{0xB7};
152+
static constexpr std::byte convertUI32F64{0xB8};
153+
static constexpr std::byte convertSI64F64{0xB9};
154+
static constexpr std::byte convertUI64F64{0xBA};
155+
156+
static constexpr std::byte promoteF32ToF64{0xBB};
157+
static constexpr std::byte reinterpretF32AsI32{0xBC};
158+
static constexpr std::byte reinterpretF64AsI64{0xBD};
159+
static constexpr std::byte reinterpretI32AsF32{0xBE};
160+
static constexpr std::byte reinterpretI64AsF64{0xBF};
161+
162+
static constexpr std::byte extendI328S{0xC0};
163+
static constexpr std::byte extendI3216S{0xC1};
164+
static constexpr std::byte extendI648S{0xC2};
165+
static constexpr std::byte extendI6416S{0xC3};
166+
static constexpr std::byte extendI6432S{0xC4};
96167
};
97168

98169
/// Byte encodings of types in Wasm binaries

0 commit comments

Comments
 (0)