1286 lines
39 KiB
TableGen
1286 lines
39 KiB
TableGen
//===- WasmSSAOps.td - WasmSSA op definitions -*- tablegen -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef WasmSSA_OPS
|
|
#define WasmSSA_OPS
|
|
|
|
|
|
include "mlir/Dialect/WasmSSA/IR/WasmSSABase.td"
|
|
include "mlir/Dialect/WasmSSA/IR/WasmSSATypes.td"
|
|
include "mlir/Dialect/WasmSSA/IR/WasmSSAInterfaces.td"
|
|
|
|
include "mlir/Interfaces/FunctionInterfaces.td"
|
|
include "mlir/Interfaces/InferTypeOpInterface.td"
|
|
include "mlir/IR/BuiltinAttributeInterfaces.td"
|
|
include "mlir/IR/SymbolInterfaces.td"
|
|
|
|
// Base class for WasmSSA operations.
|
|
// Most operations are made to match 1:1, only ignoring the stack-based approach of Wasm
|
|
// for an SSA based approach. In cases where operations match 1:1 the Wasm spec,
|
|
// no description is provided.
|
|
class WasmSSA_Op<string mnemonic, list<Trait> traits = []> :
|
|
Op<WasmSSA_Dialect, mnemonic, traits>;
|
|
|
|
class WasmSSA_BlockLikeOp<string mnemonic, string summaryStr> :
|
|
WasmSSA_Op<mnemonic, [Terminator, DeclareOpInterfaceMethods<LabelLevelOpInterface>]> {
|
|
let summary = summaryStr;
|
|
let arguments = (ins Variadic<WasmSSA_ValType>: $inputs);
|
|
let regions = (region AnyRegion: $body);
|
|
let successors = (successor AnySuccessor: $target);
|
|
let extraClassDeclaration = [{
|
|
::mlir::Block* createBlock() {
|
|
auto &block = getBody().emplaceBlock();
|
|
for (auto input : getInputs())
|
|
block.addArgument(input.getType(), input.getLoc());
|
|
return █
|
|
}
|
|
}];
|
|
let assemblyFormat = "(`(`$inputs^`)` `:` type($inputs))? attr-dict `:` $body `>` $target";
|
|
}
|
|
|
|
def WasmSSA_BlockOp : WasmSSA_BlockLikeOp<
|
|
"block",
|
|
"Create a nesting level with a label at its exit."> {
|
|
let description = [{
|
|
Defines a Wasm block, creating a new nested scope.
|
|
A block contains a body region and an optional list of input values.
|
|
Control can enter the block and later branch out to the block target.
|
|
Example:
|
|
|
|
```mlir
|
|
wasmssa.block {
|
|
|
|
// instructions
|
|
|
|
} > ^successor
|
|
```
|
|
}];
|
|
}
|
|
|
|
def WasmSSA_LoopOp : WasmSSA_BlockLikeOp<
|
|
"loop",
|
|
"Create a nesting level that define its entry as jump target."> {
|
|
let description = [{
|
|
Represents a Wasm loop construct. This defines a nesting level with
|
|
a label at the entry of the region.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
wasmssa.loop {
|
|
|
|
} > ^successor
|
|
```
|
|
}];
|
|
}
|
|
|
|
def WasmSSA_BlockReturnOp : WasmSSA_Op<"block_return", [Terminator,
|
|
DeclareOpInterfaceMethods<LabelBranchingOpInterface>]> {
|
|
let summary = "Return from the current block";
|
|
let arguments = (ins Variadic<WasmSSA_ValType>: $inputs);
|
|
let extraClassDeclaration = [{
|
|
::mlir::Block* getTarget();
|
|
}];
|
|
let description = [{
|
|
Escape from the current nesting level and return the control flow to its successor.
|
|
Optionally, mark the arguments that should be transfered to the successor block.
|
|
|
|
This shouldn't be confused with branch operations that targets the label defined
|
|
by the nesting level operation.
|
|
|
|
For instance, a `wasmssa.block_return` in a loop will give back control to the
|
|
successor of the loop, where a `branch` targeting the loop will flow back to the entry block of the loop.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
wasmssa.block_return
|
|
```
|
|
}];
|
|
let assemblyFormat = "($inputs^ `:` type($inputs))? attr-dict";
|
|
}
|
|
|
|
def WasmSSA_BranchIfOp : WasmSSA_Op<"branch_if", [
|
|
Terminator,
|
|
DeclareOpInterfaceMethods<LabelBranchingOpInterface>]> {
|
|
let summary = "Jump to target level if condition has non-zero value";
|
|
let arguments = (ins I32: $condition,
|
|
UI32Attr: $exitLevel,
|
|
Variadic<WasmSSA_ValType>: $inputs);
|
|
let description = [{
|
|
Jump to target level if the condition is has a non-zero value.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
wasmssa.branch_if %a to level 0 with args(%b : i32) else ^bb1
|
|
```
|
|
}];
|
|
let successors = (successor AnySuccessor: $elseSuccessor);
|
|
let assemblyFormat = "$condition `to` `level` $exitLevel (`with` `args` `(`$inputs^ `:` type($inputs)`)`)? `else` $elseSuccessor attr-dict";
|
|
}
|
|
|
|
def WasmSSA_ConstOp : WasmSSA_Op<"const", [
|
|
AllTypesMatch<["value", "result"]>,
|
|
ConstantExprOpTrait]> {
|
|
let summary = "Operator that represents a constant value";
|
|
let description = [{
|
|
Defines a constant value.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Example of integer constant
|
|
%a = wasmssa.const 1 : i32
|
|
|
|
// Example of floating point constant
|
|
%b = wasmssa.const 9.000000e+00 : f64
|
|
```
|
|
}];
|
|
let arguments = (ins TypedAttrInterface: $value);
|
|
let results = (outs WasmSSA_NumericType: $result);
|
|
let assemblyFormat = "$value attr-dict";
|
|
}
|
|
|
|
def WasmSSA_FuncOp : WasmSSA_Op<"func", [
|
|
AffineScope, AutomaticAllocationScope,
|
|
DeclareOpInterfaceMethods<FunctionOpInterface, ["verifyBody"]>,
|
|
IsolatedFromAbove,
|
|
Symbol]> {
|
|
let description = [{
|
|
Represents a Wasm function definition.
|
|
|
|
In Wasm function, locals and function arguments are interchangeable.
|
|
They are for instance both accessed using `local.get` instruction.
|
|
|
|
On the other hand, a function type is defined as a pair of tuples of Wasm value types.
|
|
To model this, the wasm.func operation has:
|
|
|
|
- A function type that represents the corresponding Wasm type (tuples of value types)
|
|
|
|
- Arguments of the entry block of type `!wasm<local T>`, with T the corresponding type
|
|
in the function type.
|
|
|
|
By default, `wasmssa.func` have nested visibility. Functions exported by the module
|
|
are marked with the exported attribute. This gives them public visibility.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Internal function with no arguments that returns a float32
|
|
wasmssa.func @my_f32_func() -> f32
|
|
|
|
// Exported function with no arguments that returns a float32
|
|
wasmssa.func exported @my_f32_func() -> f32
|
|
|
|
// A function that takes a local ref argument
|
|
wasmssa.func @i64_wrap(%a: !wasmssa<local ref to i64>) -> i32
|
|
```
|
|
}];
|
|
let arguments = (ins SymbolNameAttr: $sym_name,
|
|
WasmSSA_FuncTypeAttr: $functionType,
|
|
OptionalAttr<DictArrayAttr>:$arg_attrs,
|
|
OptionalAttr<DictArrayAttr>:$res_attrs,
|
|
UnitAttr: $exported);
|
|
let regions = (region AnyRegion: $body);
|
|
let extraClassDeclaration = [{
|
|
|
|
/// Create the entry block for the function with parameters wrapped in local ref.
|
|
::mlir::Block* addEntryBlock();
|
|
|
|
//===------------------------------------------------------------------===//
|
|
// FunctionOpInterface Methods
|
|
//===------------------------------------------------------------------===//
|
|
|
|
/// Returns the region on the current operation that is callable. This may
|
|
/// return null in the case of an external callable object, e.g. an external
|
|
/// function.
|
|
::mlir::Region *getCallableRegion() { return isExternal() ? nullptr : &getBody(); }
|
|
|
|
/// Returns the argument types of this function.
|
|
ArrayRef<Type> getArgumentTypes() { return getFunctionType().getInputs(); }
|
|
|
|
/// Returns the result types of this function.
|
|
ArrayRef<Type> getResultTypes() { return getFunctionType().getResults(); }
|
|
|
|
::mlir::SymbolTable::Visibility getVisibility() {
|
|
return getExported() ?
|
|
::mlir::SymbolTable::Visibility::Public :
|
|
::mlir::SymbolTable::Visibility::Nested;
|
|
};
|
|
}];
|
|
|
|
let builders = [
|
|
OpBuilder<(ins "::llvm::StringRef":$symbol, "FunctionType":$funcType )>
|
|
];
|
|
let hasCustomAssemblyFormat = 1;
|
|
}
|
|
|
|
def WasmSSA_FuncCallOp : WasmSSA_Op<"call"> {
|
|
let summary = "Calling a Wasm function";
|
|
let description = [{
|
|
Emits a call to a defined function
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.call @func_0 : () -> i32
|
|
```
|
|
}];
|
|
let arguments = (ins FlatSymbolRefAttr: $callee,
|
|
Variadic<WasmSSA_ValType>: $operands);
|
|
let results = (outs Variadic<WasmSSA_ValType>: $results);
|
|
let assemblyFormat = "$callee (`(`$operands^`)`)? attr-dict `:` functional-type($operands, $results)";
|
|
}
|
|
|
|
def WasmSSA_FuncImportOp : WasmSSA_Op<"import_func", [
|
|
Symbol,
|
|
CallableOpInterface,
|
|
ImportOpInterface]> {
|
|
let summary = "Importing a function variable";
|
|
let description = [{
|
|
Imports a function from another module
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Imports foo(i32) -> () from the module my_module
|
|
wasmssa.import_func "foo" from "my_module" as @func_0 {sym_visibility = "nested", type = (i32) -> ()}
|
|
```
|
|
}];
|
|
let arguments = (ins SymbolNameAttr: $sym_name,
|
|
StrAttr: $moduleName,
|
|
StrAttr: $importName,
|
|
WasmSSA_FuncTypeAttr: $type,
|
|
OptionalAttr<DictArrayAttr>:$arg_attrs,
|
|
OptionalAttr<DictArrayAttr>:$res_attrs);
|
|
let extraClassDeclaration = [{
|
|
bool isDeclaration() const { return true; }
|
|
|
|
Region *getCallableRegion() { return nullptr; }
|
|
|
|
::llvm::ArrayRef<Type> getArgumentTypes() {
|
|
return getType().getInputs();
|
|
}
|
|
|
|
::llvm::ArrayRef<Type> getResultTypes() {
|
|
return getType().getResults();
|
|
}
|
|
|
|
::mlir::SymbolTable::Visibility getVisibility() {
|
|
return ::mlir::SymbolTable::Visibility::Nested;
|
|
};
|
|
}];
|
|
let builders = [
|
|
OpBuilder<(ins "StringRef":$symbol,
|
|
"StringRef":$moduleName,
|
|
"StringRef":$importName,
|
|
"FunctionType": $type)>
|
|
];
|
|
let assemblyFormat = "$importName `from` $moduleName `as` $sym_name attr-dict";
|
|
}
|
|
|
|
def WasmSSA_GlobalOp : WasmSSA_Op<"global", [
|
|
AffineScope, AutomaticAllocationScope,
|
|
IsolatedFromAbove, Symbol, ConstantExpressionInitializerOpTrait]> {
|
|
let summary= "WebAssembly global value";
|
|
let arguments = (ins SymbolNameAttr: $sym_name,
|
|
WasmSSA_ValTypeAttr: $type,
|
|
UnitAttr: $isMutable,
|
|
UnitAttr: $exported);
|
|
let description = [{
|
|
WebAssembly global variable.
|
|
Body contains the initialization instructions for the variable value.
|
|
The body must contain only instructions considered `const` in a webassembly context,
|
|
such as `wasmssa.const` or `global.get`.
|
|
|
|
By default, `wasmssa.global` have nested visibility. Global exported by the module
|
|
are marked with the exported attribute. This gives them public visibility.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Define module_global_var, an internal mutable i32 global variable equal to 10.
|
|
wasmssa.global @module_global_var i32 mutable : {
|
|
%[[VAL_0:.*]] = wasmssa.const 10 : i32
|
|
wasmssa.return %[[VAL_0]] : i32
|
|
}
|
|
|
|
// Define global_var, an exported constant i32 global variable equal to 42.
|
|
wasmssa.global @global_var i32 : {
|
|
%[[VAL_0:.*]] = wasmssa.const 42 : i32
|
|
wasmssa.return %[[VAL_0]] : i32
|
|
}
|
|
```
|
|
}];
|
|
let regions = (region AnyRegion: $initializer);
|
|
|
|
let extraClassDeclaration = [{
|
|
::mlir::SymbolTable::Visibility getVisibility() {
|
|
return getExported() ?
|
|
::mlir::SymbolTable::Visibility::Public :
|
|
::mlir::SymbolTable::Visibility::Nested;
|
|
};
|
|
}];
|
|
let hasCustomAssemblyFormat = 1;
|
|
}
|
|
|
|
def WasmSSA_GlobalImportOp : WasmSSA_Op<"import_global", [
|
|
Symbol,
|
|
ImportOpInterface]> {
|
|
let summary = "Importing a global variable";
|
|
let description = [{
|
|
Imports a global from another module
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Imports the "glob" i32 global from the module my_module as "global_0"
|
|
wasmssa.import_global "glob" from "my_module" as @global_0 nested : i32
|
|
```
|
|
}];
|
|
let arguments = (ins SymbolNameAttr: $sym_name,
|
|
StrAttr: $moduleName,
|
|
StrAttr: $importName,
|
|
WasmSSA_ValTypeAttr: $type,
|
|
UnitAttr: $isMutable);
|
|
let extraClassDeclaration = [{
|
|
bool isDeclaration() const { return true; }
|
|
|
|
::mlir::SymbolTable::Visibility getVisibility() {
|
|
return ::mlir::SymbolTable::Visibility::Nested;
|
|
};
|
|
}];
|
|
let hasCustomAssemblyFormat = 1;
|
|
}
|
|
|
|
def WasmSSA_GlobalGetOp : WasmSSA_Op<"global_get", [DeclareOpInterfaceMethods<SymbolUserOpInterface>,
|
|
ConstantExprOpTrait]> {
|
|
let summary = "Returns the value of the global passed as argument.";
|
|
let description = [{
|
|
Retrieves the value of the global passed as argument and stores it in a
|
|
variable
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Gets the value of `@global_0` and stores its value in %a
|
|
%a = wasmssa.global_get @global_0 : i32
|
|
```
|
|
}];
|
|
let arguments = (ins FlatSymbolRefAttr: $global);
|
|
let results = (outs WasmSSA_ValType: $global_val);
|
|
let assemblyFormat = "$global attr-dict `:` type($global_val)";
|
|
}
|
|
|
|
def WasmSSA_IfOp : WasmSSA_Op<"if", [Terminator,
|
|
DeclareOpInterfaceMethods<LabelLevelOpInterface>]> {
|
|
let summary = "Execute the if region if condition value is non-zero, the else region otherwise.";
|
|
let description = [{
|
|
Execute the if region if the condition is non-zero. Otherwise the else region is executed.
|
|
The else region can be empty but must return the same datatype as the if region.
|
|
If clauses can be nested.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Runs the if clause is %a is non-zero
|
|
wasmssa.if %a {
|
|
// Execute if %a is non-zero
|
|
} else {
|
|
// else clause
|
|
}
|
|
```
|
|
}];
|
|
let arguments = (ins I32:$condition, Variadic<WasmSSA_ValType>: $inputs);
|
|
let regions = (region AnyRegion: $if, AnyRegion: $else);
|
|
let successors = (successor AnySuccessor: $target);
|
|
let extraClassDeclaration = [{
|
|
private:
|
|
inline ::mlir::Block* createBlock(::mlir::Region& region) {
|
|
assert(region.empty() && "Creating entry block on non empty region");
|
|
assert(region.getParentOp() == this->getOperation() &&
|
|
"Creating block for region that isn't part of the current op");
|
|
auto &block = region.emplaceBlock();
|
|
for (auto input : getInputs())
|
|
block.addArgument(input.getType(), input.getLoc());
|
|
return █
|
|
}
|
|
|
|
public:
|
|
::mlir::Block* createIfBlock() {
|
|
return createBlock(getIf());
|
|
}
|
|
::mlir::Block* createElseBlock() {
|
|
return createBlock(getElse());
|
|
}
|
|
}];
|
|
let assemblyFormat = "$condition (`(`$inputs^`)` `:` type($inputs))? attr-dict `:` $if custom<ElseRegion>($else) `>` $target";
|
|
}
|
|
|
|
def WasmSSA_LocalOp : WasmSSA_Op<"local", [
|
|
DeclareOpInterfaceMethods<InferTypeOpInterface>]> {
|
|
let summary = "Declaration of local variable";
|
|
let description = [{
|
|
Declares a local variable
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Declares `%a`, a float32 local
|
|
%a = wasmssa.local of type f32
|
|
```
|
|
}];
|
|
let arguments = (ins WasmSSA_ValTypeAttr: $type);
|
|
let results = (outs WasmSSA_LocalRef: $result);
|
|
let assemblyFormat = "`of` `type` $type attr-dict";
|
|
}
|
|
|
|
def WasmSSA_LocalGetOp : WasmSSA_Op<"local_get", [
|
|
DeclareOpInterfaceMethods<InferTypeOpInterface>]> {
|
|
let summary = "Set local to value and return the operand.";
|
|
let description = [{
|
|
Gets the value of a local variable and returns a reference to it.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Retrieves a reference to `%a`, a float32 local
|
|
%b = wasmssa.local_get %a : ref to f32
|
|
```
|
|
}];
|
|
let arguments = (ins WasmSSA_LocalRef: $localVar);
|
|
let results = (outs WasmSSA_ValType: $result);
|
|
let assemblyFormat = "$localVar `:` type($localVar) attr-dict";
|
|
}
|
|
|
|
def WasmSSA_LocalSetOp : WasmSSA_Op<"local_set"> {
|
|
let summary = "Set local to given value";
|
|
let description = [{
|
|
Sets the value of a local variable.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Sets `%d`, to the value of `%c`
|
|
wasmssa.local_set %d : ref to i32 to %c : i32
|
|
```
|
|
}];
|
|
let arguments = (ins WasmSSA_LocalRef: $localVar,
|
|
WasmSSA_ValType: $value);
|
|
let hasVerifier = 1;
|
|
let assemblyFormat = "$localVar `:` type($localVar) `to` $value `:` type($value) attr-dict";
|
|
}
|
|
|
|
def WasmSSA_LocalTeeOp : WasmSSA_Op<"local_tee", [
|
|
DeclareOpInterfaceMethods<InferTypeOpInterface>]> {
|
|
let summary = "Set local to value and return the operand.";
|
|
let description = [{
|
|
Sets the value of a local variable and returns it.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Sets `%b`, to the value of `%c` and returns it in %a
|
|
%a = wasmssa.local_tee %b : ref to i32 to %c : i32
|
|
```
|
|
}];
|
|
let arguments = (ins WasmSSA_LocalRef: $localVar,
|
|
WasmSSA_ValType: $value);
|
|
let results = (outs WasmSSA_ValType: $result);
|
|
let hasVerifier = 1;
|
|
let assemblyFormat = "$localVar `:` type($localVar) `to` $value `:` type($value) attr-dict";
|
|
}
|
|
|
|
def WasmSSA_MemOp : WasmSSA_Op<"memory", [Symbol]> {
|
|
let summary= "WebAssembly memory definition";
|
|
let description = [{
|
|
Define a memory to be used by the program.
|
|
Multiple memories can be defined in the same module.
|
|
|
|
By default, `wasmssa.memory` have nested visibility. Memory exported by
|
|
the module are marked with the exported attribute. This gives them public
|
|
visibility.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Define the `mem_0` (internal) memory with defined size bounds of [0:65536]
|
|
wasmssa.memory @mem_0 !wasmssa<limit[0:65536]>
|
|
|
|
// Define the `mem_1` exported memory with minimal size of 512
|
|
wasmssa.memory exported @mem_1 !wasmssa<limit[512:]>
|
|
```
|
|
}];
|
|
let arguments = (ins SymbolNameAttr: $sym_name,
|
|
WasmSSA_LimitTypeAttr: $limits,
|
|
UnitAttr: $exported);
|
|
|
|
let extraClassDeclaration = [{
|
|
::mlir::SymbolTable::Visibility getVisibility() {
|
|
return getExported() ?
|
|
::mlir::SymbolTable::Visibility::Public :
|
|
::mlir::SymbolTable::Visibility::Nested;
|
|
};
|
|
}];
|
|
|
|
let assemblyFormat = "(`exported` $exported^)? $sym_name $limits attr-dict";
|
|
}
|
|
|
|
def WasmSSA_MemImportOp : WasmSSA_Op<"import_mem", [Symbol, ImportOpInterface]> {
|
|
let summary = "Importing a memory";
|
|
let description = [{
|
|
Import a memory from another module.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Import the memory `mem` from `my_module` as @mem_0
|
|
wasmssa.import_mem "mem" from "my_module" as @mem_0 {limits = !wasmssa<limit[2:]>}
|
|
```
|
|
}];
|
|
let arguments = (ins SymbolNameAttr: $sym_name,
|
|
StrAttr: $moduleName,
|
|
StrAttr: $importName,
|
|
WasmSSA_LimitTypeAttr: $limits);
|
|
let extraClassDeclaration = [{
|
|
bool isDeclaration() const { return true; }
|
|
::mlir::SymbolTable::Visibility getVisibility() {
|
|
return ::mlir::SymbolTable::Visibility::Nested;
|
|
};
|
|
}];
|
|
let assemblyFormat = "$importName `from` $moduleName `as` $sym_name attr-dict";
|
|
}
|
|
|
|
def WasmSSA_TableOp : WasmSSA_Op<"table", [Symbol]> {
|
|
let summary= "WebAssembly table value";
|
|
let arguments = (ins SymbolNameAttr: $sym_name,
|
|
WasmSSA_TableTypeAttr: $type,
|
|
UnitAttr: $exported);
|
|
let extraClassDeclaration = [{
|
|
::mlir::SymbolTable::Visibility getVisibility() {
|
|
return getExported() ?
|
|
::mlir::SymbolTable::Visibility::Public :
|
|
::mlir::SymbolTable::Visibility::Nested;
|
|
};
|
|
}];
|
|
let assemblyFormat = "(`exported` $exported^)? $sym_name $type attr-dict";
|
|
}
|
|
|
|
def WasmSSA_TableImportOp : WasmSSA_Op<"import_table", [Symbol, ImportOpInterface]> {
|
|
let summary = "Importing a table";
|
|
let description = [{
|
|
Import a table from another module.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Import the table `table` from `my_module` as @table_0
|
|
wasmssa.import_table "table" from "my_module" as @table_0 {type = !wasmssa<tabletype !wasmssa.funcref [2:]>}
|
|
```
|
|
}];
|
|
let arguments = (ins SymbolNameAttr: $sym_name,
|
|
StrAttr: $moduleName,
|
|
StrAttr: $importName,
|
|
WasmSSA_TableTypeAttr: $type);
|
|
let extraClassDeclaration = [{
|
|
bool isDeclaration() const { return true; }
|
|
::mlir::SymbolTable::Visibility getVisibility() {
|
|
return ::mlir::SymbolTable::Visibility::Nested;
|
|
};
|
|
}];
|
|
let assemblyFormat = "$importName `from` $moduleName `as` $sym_name attr-dict";
|
|
}
|
|
|
|
def WasmSSA_ReturnOp : WasmSSA_Op<"return", [Terminator]> {
|
|
let summary = "Return from the current function frame";
|
|
let arguments = (ins Variadic<WasmSSA_ValType>: $operands);
|
|
let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
|
|
let builders = [
|
|
OpBuilder<(ins)>
|
|
];
|
|
}
|
|
|
|
// ---- Numeric ops
|
|
|
|
class WasmSSA_BinaryNumericalOp<string mnemonic, string summaryStr, string descStr,
|
|
list<Type> validOpTypes> :
|
|
WasmSSA_Op<mnemonic, [AllTypesMatch<["lhs", "rhs", "result"]>]> {
|
|
let summary = summaryStr;
|
|
let description = descStr;
|
|
let arguments = (ins AnyTypeOf<validOpTypes>:$lhs, AnyTypeOf<validOpTypes>:$rhs);
|
|
let results = (outs AnyTypeOf<validOpTypes>:$result);
|
|
let assemblyFormat = "$lhs $rhs `:` type($lhs) attr-dict";
|
|
}
|
|
|
|
def WasmSSA_AddOp : WasmSSA_BinaryNumericalOp<"add",
|
|
"Sum two values",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.add %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_NumericType]>{}
|
|
|
|
def WasmSSA_AndOp : WasmSSA_BinaryNumericalOp<"and",
|
|
"Compute the bitwise AND between two values",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.and %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_NumericType]>{}
|
|
|
|
def WasmSSA_DivOp : WasmSSA_BinaryNumericalOp<"div",
|
|
"Division between floating point values",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.div %b %c : f32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_DivUIOp : WasmSSA_BinaryNumericalOp<"div_ui",
|
|
"Divide values interpreted as unsigned int",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.div_ui %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_DivSIOp : WasmSSA_BinaryNumericalOp<"div_si",
|
|
"Divide values interpreted as signed int",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.div_si %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_MulOp : WasmSSA_BinaryNumericalOp<"mul",
|
|
"Multiply two values",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.mul %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_NumericType]>{}
|
|
|
|
def WasmSSA_OrOp : WasmSSA_BinaryNumericalOp<"or",
|
|
"Compute the bitwise OR of two values",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.or %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_NumericType]>{}
|
|
|
|
def WasmSSA_SubOp : WasmSSA_BinaryNumericalOp<"sub",
|
|
"Subtract two values",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.sub %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_NumericType]>{}
|
|
|
|
def WasmSSA_RemUIOp : WasmSSA_BinaryNumericalOp<"rem_ui",
|
|
"Calculate the remainder of dividing two integer values as an unsigned integer",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.rem_ui %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_RemSIOp : WasmSSA_BinaryNumericalOp<"rem_si",
|
|
"Calculate the remainder of dividing two integer values as signed integer",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.rem_si %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_XOrOp : WasmSSA_BinaryNumericalOp<"xor",
|
|
"Compute the bitwise XOR of two values",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.xor %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_NumericType]>{}
|
|
|
|
def WasmSSA_MinOp : WasmSSA_BinaryNumericalOp<"min",
|
|
"Compute the minimum of two floating point values.",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.min %b %c : f32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_MaxOp : WasmSSA_BinaryNumericalOp<"max",
|
|
"Compute the minimum of two floating point values.",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.max %b %c : f32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_CopySignOp : WasmSSA_BinaryNumericalOp<"copysign",
|
|
"Copy sign from one floating point value to the other.",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.copysign %b %c : f32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
class WasmSSA_BinaryComparisonOp<string mnemonic, string summaryStr, string descStr,
|
|
list<Type> validOpTypes> :
|
|
WasmSSA_Op<mnemonic, [AllTypesMatch<["lhs", "rhs"]>]> {
|
|
let summary = summaryStr;
|
|
let description = descStr;
|
|
let arguments = (ins AnyTypeOf<validOpTypes>:$lhs, AnyTypeOf<validOpTypes>:$rhs);
|
|
let results = (outs I32:$result);
|
|
let assemblyFormat = "$lhs $rhs `:` type($lhs) `->` type($result) attr-dict";
|
|
}
|
|
|
|
def WasmSSA_EqOp : WasmSSA_BinaryComparisonOp<"eq",
|
|
"Check if two values are equal",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.eq %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_NumericType]>{}
|
|
|
|
def WasmSSA_NeOp : WasmSSA_BinaryComparisonOp<"ne",
|
|
"Check if two values are different",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.ne %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_NumericType]>{}
|
|
|
|
def WasmSSA_LtSIOp : WasmSSA_BinaryComparisonOp<"lt_si",
|
|
"Check if a signed integer value is less than another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.lt_si %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_LtUIOp : WasmSSA_BinaryComparisonOp<"lt_ui",
|
|
"Check if an unsigned integer value is less than another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.lt_ui %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_LeSIOp : WasmSSA_BinaryComparisonOp<"le_si",
|
|
"Check if a signed integer value is less or equal to another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.le_si %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_LeUIOp : WasmSSA_BinaryComparisonOp<"le_ui",
|
|
"Check if an unsigned integer value is less or equal to another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.le_ui %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_GtSIOp : WasmSSA_BinaryComparisonOp<"gt_si",
|
|
"Check if a signed integer value is greater than another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.gt_si %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_GtUIOp : WasmSSA_BinaryComparisonOp<"gt_ui",
|
|
"Check if an unsigned integer value is greater than another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.gt_ui %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_GeSIOp : WasmSSA_BinaryComparisonOp<"ge_si",
|
|
"Check if a signed integer value is greater or equal to another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.ge_si %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_GeUIOp : WasmSSA_BinaryComparisonOp<"ge_ui",
|
|
"Check if an unsigned integer value is greater or equal to another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.ge_ui %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_LtOp : WasmSSA_BinaryComparisonOp<"lt",
|
|
"Check if a float value is less than another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.lt %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_LeOp : WasmSSA_BinaryComparisonOp<"le",
|
|
"Check if a float value is less or equal to another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.le %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_GtOp : WasmSSA_BinaryComparisonOp<"gt",
|
|
"Check if a float value is greater than another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.gt %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_GeOp : WasmSSA_BinaryComparisonOp<"ge",
|
|
"Check if a float value is greater or equal to another",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.ge %b %c : i32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
// Integer shift and rotate operations.
|
|
class WasmSSA_ShiftRotateOp<string mnemonic, string summaryStr, string descStr> :
|
|
WasmSSA_Op<mnemonic, [AllTypesMatch<["val", "bits", "result"]>]> {
|
|
let summary = summaryStr;
|
|
let description = descStr;
|
|
let arguments = (ins WasmSSA_IntegerType:$val, WasmSSA_IntegerType:$bits);
|
|
let results = (outs WasmSSA_IntegerType:$result);
|
|
let assemblyFormat = "$val `by` $bits `bits` `:` type($val) attr-dict";
|
|
}
|
|
|
|
def WasmSSA_ShLOp : WasmSSA_ShiftRotateOp<"shl",
|
|
[{Consume an integer and an integer shift amount. The first
|
|
integer shall be shifted left by N bits, where N is the value of the second
|
|
integer.}],
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.shl %b by %c bits : i64
|
|
```
|
|
}]
|
|
>{}
|
|
|
|
def WasmSSA_ShRSOp : WasmSSA_ShiftRotateOp<"shr_s",
|
|
[{Arithmetic right shift.
|
|
|
|
Consume an integer and an integer shift amount. The first
|
|
integer shall be shifted right by N bits, where N is the value of the
|
|
second integer.
|
|
|
|
Vacated bits on the left shall be filled with the sign bit.}],
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.shr_s %b by %c bits : i64
|
|
```
|
|
}]
|
|
>{}
|
|
|
|
def WasmSSA_ShRUOp : WasmSSA_ShiftRotateOp<"shr_u",
|
|
[{Logical right shift.
|
|
|
|
Consume an integer, and an integer shift amount. The first
|
|
integer shall be shifted right by N bits, where N is the value of the
|
|
second integer.
|
|
|
|
Vacated bits on the left shall be filled with zeroes.}],
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.shr_u %b by %c bits : i64
|
|
```
|
|
}]
|
|
>{}
|
|
|
|
def WasmSSA_RotlOp : WasmSSA_ShiftRotateOp<"rotl",
|
|
[{Rotate left.
|
|
|
|
Consume an integer and an integer rotate. The first
|
|
integer shall be rotated left by N bits, where N is the value of the
|
|
second integer.}],
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.rotl %b by %c bits : i64
|
|
```
|
|
}]
|
|
>{}
|
|
|
|
def WasmSSA_RotrOp : WasmSSA_ShiftRotateOp<"rotr",
|
|
[{Rotate right.
|
|
|
|
Consume an integer, and an integer rotate. The first
|
|
integer shall be rotated right by N bits, where N is the value of the
|
|
second integer.}],
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.rotr %b by %c bits : i64
|
|
```
|
|
}]
|
|
>{}
|
|
|
|
class WasmSSA_ConversionOp<string mnemonic, string summaryStr, string descStr,
|
|
list<Type> ValidInputTypes,
|
|
list<Type> ValidOutputTypes> :
|
|
WasmSSA_Op<mnemonic> {
|
|
let summary = summaryStr;
|
|
let description = descStr;
|
|
let arguments = (ins AnyTypeOf<ValidInputTypes>:$input);
|
|
let results = (outs AnyTypeOf<ValidOutputTypes>:$result);
|
|
let assemblyFormat = "$input `:` type($input) `to` type($result) attr-dict";
|
|
}
|
|
|
|
def WasmSSA_ConvertUOp : WasmSSA_ConversionOp<"convert_u",
|
|
[{Convert integer, interpreted as binary encoded positive value, to floating-point value.
|
|
|
|
Consume an integer and produces a floating point value containing the rounded value of the original operand. Rounding is round to nearest, tie to even.}],
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.convert_u %b : i32 to f64
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_ConvertSOp : WasmSSA_ConversionOp<"convert_s",
|
|
[{Convert integer interpreted as 2's complement signed value to floating-point value.
|
|
|
|
Consume an integer and produces a floating point value containing the rounded value of the original operand. Rounding is round to nearest, tie to even.}],
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.convert_s %b : i32 to f64
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_TruncSIOp : WasmSSA_ConversionOp<"trunc_si",
|
|
[{Truncate floating point value to signed integer.
|
|
|
|
Consume a floating point value and produces a signed integer holding the value truncated toward zero.
|
|
Traps if the value is NaN, is infinity, or is outside the range of the target integer type.}],
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.trunc_si %b : f32 to i32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_TruncUIOp : WasmSSA_ConversionOp<"trunc_ui",
|
|
[{Truncate floating point value to unsigned integer.
|
|
|
|
Consume a floating point value and produces an unsigned integer holding the value truncated toward zero.
|
|
Traps if the value is NaN, is infinity, is negative, or is outside the range of the target integer type.}],
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.trunc_ui %b : f32 to i32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_DemoteOp : WasmSSA_ConversionOp<"demote",
|
|
"Convert a f64 value to f32",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.demote %b : f64 to f32
|
|
```
|
|
}],
|
|
[F64],
|
|
[F32]>{}
|
|
|
|
def WasmSSA_ExtendSI32Op : WasmSSA_Op<"extend_i32_s">{
|
|
let summary = [{Sign extend i32 to i64.}];
|
|
let description = [{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.extend_i32_s %b to i64
|
|
```
|
|
}];
|
|
let arguments = (ins I32:$input);
|
|
let results = (outs I64:$result);
|
|
let assemblyFormat = "$input `to` type($result) attr-dict";
|
|
}
|
|
|
|
def WasmSSA_ExtendUI32Op : WasmSSA_Op<"extend_i32_u">{
|
|
let summary = [{Zero extend i32 to i64.}];
|
|
let description = [{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.extend_i32_s %b to i64
|
|
```
|
|
}];
|
|
let arguments = (ins I32:$input);
|
|
let results = (outs I64:$result);
|
|
let assemblyFormat = "$input `to` type($result) attr-dict";
|
|
}
|
|
|
|
def WasmSSA_ExtendLowBitsSOp : WasmSSA_Op<"extend", [AllTypesMatch<["input", "result"]>]> {
|
|
let summary = "";
|
|
let description = [{
|
|
Extend low bytes of a value to fit a given width.
|
|
For instance, signed extension from 8 low bits of the 32-bits integer value
|
|
254 (0x000000FE) would produce the value -2 (0xFFFFFFFE).
|
|
|
|
This corresponds to the `extendnn` instruction of Wasm, which shouldn't be
|
|
confused with the `extend_inn` Wasm instruction, for which all input bits
|
|
are used and widened to wider output type.
|
|
In this operation, input and output types are the same.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.extend 16 low bits from %[[VAL_0]]: i64
|
|
```
|
|
}];
|
|
let arguments = (ins WasmSSA_IntegerType:$input, Builtin_IntegerAttr: $bitsToTake);
|
|
let results = (outs WasmSSA_IntegerType: $result);
|
|
let hasVerifier = 1;
|
|
let assemblyFormat = "$bitsToTake `low` `bits` `from` $input `:` type($input) attr-dict";
|
|
}
|
|
|
|
def WasmSSA_PromoteOp : WasmSSA_ConversionOp<"promote",
|
|
"Get f64 representation of a f32 value.",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.promote %b : f32 to f64
|
|
```
|
|
}],
|
|
[Builtin_Float32],
|
|
[Builtin_Float64]>{}
|
|
|
|
def WasmSSA_WrapOp : WasmSSA_ConversionOp<"wrap",
|
|
"Cast an i64 to i32 by using a wrapping mechanism: y = x mod 2^32",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.wrap %b : i64 to i32
|
|
```
|
|
}],
|
|
[I64],
|
|
[I32]>{}
|
|
|
|
// Reinterpret ops are basically all one-offs. They all have an unique,
|
|
// type-postfixed opcode, and support exactly one input and output type.
|
|
def WasmSSA_ReinterpretOp : WasmSSA_ConversionOp<"reinterpret",
|
|
[{Reinterpret the value represented by a bit vector by
|
|
bit-casting it to another type of same representation width.}],
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.reinterpret %b : f32 as i32
|
|
```
|
|
}],
|
|
[WasmSSA_NumericType], [WasmSSA_NumericType]>{
|
|
let assemblyFormat = "$input `:` type($input) `as` type($result) attr-dict";
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
class WasmSSA_UnaryNumericalOp<string mnemonic,
|
|
string summaryStr,
|
|
string descStr,
|
|
list<Type> validOpTypes> :
|
|
WasmSSA_Op<mnemonic, [AllTypesMatch<["src", "result"]>]> {
|
|
let summary = summaryStr;
|
|
let description = descStr;
|
|
let arguments = (ins AnyTypeOf<validOpTypes>:$src);
|
|
let results = (outs AnyTypeOf<validOpTypes>:$result);
|
|
let assemblyFormat = "$src`:` type($src) attr-dict";
|
|
}
|
|
|
|
def WasmSSA_AbsOp : WasmSSA_UnaryNumericalOp<"abs",
|
|
"Floating point absolute value",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.abs %b : f32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_CeilOp : WasmSSA_UnaryNumericalOp<"ceil",
|
|
"Ceil rounding of floating point value",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.ceil %b : f32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_FloorOp : WasmSSA_UnaryNumericalOp<"floor",
|
|
"Floor rounding of floating point value",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.floor %b : f32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_NegOp : WasmSSA_UnaryNumericalOp<"neg",
|
|
"Floating point negation",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.neg %b : f32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_SqrtOp : WasmSSA_UnaryNumericalOp<"sqrt",
|
|
"Floating point square root",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.sqrt %b : f32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_TruncOp : WasmSSA_UnaryNumericalOp<"trunc",
|
|
"Trunc of floating point value",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.trunc %b : f32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_NearestOp : WasmSSA_UnaryNumericalOp<"nearest",
|
|
"Round floating point value to the nearest integer, ties to even",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.nearest %b : f32
|
|
```
|
|
}],
|
|
[WasmSSA_FPType]>{}
|
|
|
|
def WasmSSA_CtzOp : WasmSSA_UnaryNumericalOp<"ctz",
|
|
"Count trailing zeroes of an integer",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.ctz %b : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_ClzOp : WasmSSA_UnaryNumericalOp<"clz",
|
|
"Count leading zeroes of an integer",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.clz %b : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
def WasmSSA_EqzOp : WasmSSA_Op<"eqz", []> {
|
|
let summary = "Check if the given value is equal to zero";
|
|
let description =
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.eqz %b : i64 -> i32
|
|
```
|
|
}];
|
|
let arguments = (ins WasmSSA_IntegerType: $input);
|
|
let results = (outs I32: $result);
|
|
let assemblyFormat = "$input`:` type($input) `->` type($result) attr-dict";
|
|
}
|
|
|
|
|
|
def WasmSSA_PopCntOp : WasmSSA_UnaryNumericalOp<"popcnt",
|
|
"Population count of an integer.",
|
|
[{Example:
|
|
|
|
```mlir
|
|
%a = wasmssa.popcnt %b : i32
|
|
```
|
|
}],
|
|
[WasmSSA_IntegerType]>{}
|
|
|
|
|
|
#endif // WasmSSA_OPS
|