[Mlir-commits] [mlir] [MLIR][WasmSSA] Add global_set and select ops (PR #196613)
Byeongjee Kang
llvmlistbot at llvm.org
Thu Jul 23 07:45:00 PDT 2026
https://github.com/byeongjee updated https://github.com/llvm/llvm-project/pull/196613
>From 4eb1075004eafe159cdb9b436cb5a4fb9a2a33b4 Mon Sep 17 00:00:00 2001
From: Byeongjee Kang <byeongjee.kang at gmail.com>
Date: Fri, 8 May 2026 00:20:59 -0400
Subject: [PATCH 1/2] [MLIR][WasmSSA] Add global_set op
Adds the `wasmssa.global_set` operation, which writes a value to a
mutable global variable. The op verifies that the referenced symbol is
a `wasmssa.global` or `wasmssa.import_global` marked mutable, and that
the operand type matches the global's declared type.
---
.../mlir/Dialect/WasmSSA/IR/WasmSSAOps.td | 19 +++++++
mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp | 38 +++++++++++++
.../Dialect/WasmSSA/custom_parser/global.mlir | 12 ++++
mlir/test/Dialect/WasmSSA/global-invalid.mlir | 55 +++++++++++++++++++
4 files changed, 124 insertions(+)
diff --git a/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td b/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
index bfa0953f50ac8..e2fb642433266 100644
--- a/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
+++ b/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
@@ -381,6 +381,25 @@ def WasmSSA_GlobalGetOp : WasmSSA_Op<"global_get", [DeclareOpInterfaceMethods<Sy
let assemblyFormat = "$global attr-dict `:` type($global_val)";
}
+def WasmSSA_GlobalSetOp : WasmSSA_Op<"global_set", [
+ DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
+ let summary = "Sets the value of the mutable global passed as argument.";
+ let description = [{
+ Sets the value of the mutable global referenced by the symbol to the given
+ value.
+
+ Example:
+
+ ```mlir
+ // Sets the value of `@global_0` to `%v`.
+ wasmssa.global_set @global_0 to %v : i32
+ ```
+ }];
+ let arguments = (ins FlatSymbolRefAttr: $global,
+ WasmSSA_ValType: $value);
+ let assemblyFormat = "$global `to` $value `:` type($value) attr-dict";
+}
+
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.";
diff --git a/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp b/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp
index 08de887a56a97..eab9c7a9d53a7 100644
--- a/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp
+++ b/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp
@@ -331,6 +331,44 @@ GlobalGetOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
return success();
}
+//===----------------------------------------------------------------------===//
+// GlobalSetOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+GlobalSetOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
+ Operation *symTabOp = SymbolTable::getNearestSymbolTable(*this);
+ StringRef referencedSymbol = getGlobal();
+ Operation *definitionOp = symbolTable.lookupSymbolIn(
+ symTabOp, StringAttr::get(this->getContext(), referencedSymbol));
+ if (!definitionOp)
+ return emitError() << "symbol @" << referencedSymbol << " is undefined";
+
+ Type globalType;
+ bool isMutable = false;
+ if (auto global = dyn_cast<GlobalOp>(definitionOp)) {
+ globalType = global.getType();
+ isMutable = global.getIsMutable();
+ } else if (auto globalImport = dyn_cast<GlobalImportOp>(definitionOp)) {
+ globalType = globalImport.getType();
+ isMutable = globalImport.getIsMutable();
+ } else {
+ return emitError() << "symbol @" << referencedSymbol
+ << " is not a global symbol";
+ }
+
+ if (!isMutable)
+ return emitError("global.set target must be mutable");
+
+ Type valueType = getValue().getType();
+ if (globalType != valueType)
+ return emitError("global.set value type does not match target global "
+ "type: expected ")
+ << globalType << " but got " << valueType;
+
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// GlobalImportOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/WasmSSA/custom_parser/global.mlir b/mlir/test/Dialect/WasmSSA/custom_parser/global.mlir
index a25abbd2a8662..6441731a0a335 100644
--- a/mlir/test/Dialect/WasmSSA/custom_parser/global.mlir
+++ b/mlir/test/Dialect/WasmSSA/custom_parser/global.mlir
@@ -19,6 +19,12 @@ module {
%0 = wasmssa.global_get @global_0 : i32
wasmssa.return %0 : i32
}
+
+ wasmssa.func @set_global() {
+ %0 = wasmssa.const 7 : i32
+ wasmssa.global_set @global_2 to %0 : i32
+ wasmssa.return
+ }
}
// CHECK-LABEL: wasmssa.import_global "from_js" from "env" as @global_0 : i32
@@ -42,3 +48,9 @@ module {
// CHECK: %[[VAL_0:.*]] = wasmssa.global_get @global_0 : i32
// CHECK: wasmssa.return %[[VAL_0]] : i32
// CHECK: }
+
+// CHECK-LABEL: wasmssa.func @set_global() {
+// CHECK: %[[VAL_0:.*]] = wasmssa.const 7 : i32
+// CHECK: wasmssa.global_set @global_2 to %[[VAL_0]] : i32
+// CHECK: wasmssa.return
+// CHECK: }
diff --git a/mlir/test/Dialect/WasmSSA/global-invalid.mlir b/mlir/test/Dialect/WasmSSA/global-invalid.mlir
index c5bc606fd13f3..600b2f0715fdc 100644
--- a/mlir/test/Dialect/WasmSSA/global-invalid.mlir
+++ b/mlir/test/Dialect/WasmSSA/global-invalid.mlir
@@ -40,3 +40,58 @@ module {
wasmssa.return %0 : i32
}
}
+
+// -----
+
+module {
+ wasmssa.func @f() {
+ %0 = wasmssa.const 1 : i32
+ // expected-error at +1 {{symbol @missing is undefined}}
+ wasmssa.global_set @missing to %0 : i32
+ wasmssa.return
+ }
+}
+
+// -----
+
+module {
+ wasmssa.global @global_0 i32 : {
+ %0 = wasmssa.const 0 : i32
+ wasmssa.return %0 : i32
+ }
+ wasmssa.func @f() {
+ %0 = wasmssa.const 1 : i32
+ // expected-error at +1 {{global.set target must be mutable}}
+ wasmssa.global_set @global_0 to %0 : i32
+ wasmssa.return
+ }
+}
+
+// -----
+
+module {
+ wasmssa.global @global_0 i64 mutable : {
+ %0 = wasmssa.const 0 : i64
+ wasmssa.return %0 : i64
+ }
+ wasmssa.func @f() {
+ %0 = wasmssa.const 1 : i32
+ // expected-error at +1 {{global.set value type does not match target global type: expected 'i64' but got 'i32'}}
+ wasmssa.global_set @global_0 to %0 : i32
+ wasmssa.return
+ }
+}
+
+// -----
+
+module {
+ wasmssa.func @not_global() {
+ wasmssa.return
+ }
+ wasmssa.func @f() {
+ %0 = wasmssa.const 1 : i32
+ // expected-error at +1 {{symbol @not_global is not a global symbol}}
+ wasmssa.global_set @not_global to %0 : i32
+ wasmssa.return
+ }
+}
>From c9c103386c84a4756f84bbf3a60cbfb07076b541 Mon Sep 17 00:00:00 2001
From: Byeongjee Kang <byeongjee.kang at gmail.com>
Date: Fri, 8 May 2026 15:05:35 -0400
Subject: [PATCH 2/2] [MLIR][WasmSSA] Add select op
Adds the `wasmssa.select` operation, a Wasm value-typed ternary that
returns one of two operands based on an i32 condition. The op uses the
`AllTypesMatch` trait to require both branches and the result share the
same Wasm value type, and is marked `Pure` since it has no side effects.
Also adds the `SideEffectInterfaces` td/header includes needed by the
`Pure` trait.
---
.../include/mlir/Dialect/WasmSSA/IR/WasmSSA.h | 1 +
.../mlir/Dialect/WasmSSA/IR/WasmSSAOps.td | 24 ++++++++++++
.../Dialect/WasmSSA/custom_parser/select.mlir | 37 +++++++++++++++++++
3 files changed, 62 insertions(+)
create mode 100644 mlir/test/Dialect/WasmSSA/custom_parser/select.mlir
diff --git a/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSA.h b/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSA.h
index 64391d807c633..64d480c065b79 100644
--- a/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSA.h
+++ b/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSA.h
@@ -38,6 +38,7 @@
#include "mlir/Interfaces/CallInterfaces.h"
#include "mlir/Interfaces/FunctionInterfaces.h"
#include "mlir/Interfaces/InferTypeOpInterface.h"
+#include "mlir/Interfaces/SideEffectInterfaces.h"
//===----------------------------------------------------------------------===//
// WebAssembly Constraints
diff --git a/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td b/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
index e2fb642433266..3b3c3e8825fef 100644
--- a/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
+++ b/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
@@ -16,6 +16,7 @@ include "mlir/Dialect/WasmSSA/IR/WasmSSAInterfaces.td"
include "mlir/Interfaces/FunctionInterfaces.td"
include "mlir/Interfaces/InferTypeOpInterface.td"
+include "mlir/Interfaces/SideEffectInterfaces.td"
include "mlir/IR/BuiltinAttributeInterfaces.td"
include "mlir/IR/SymbolInterfaces.td"
@@ -628,6 +629,29 @@ def WasmSSA_ReturnOp : WasmSSA_Op<"return", [Terminator]> {
];
}
+def WasmSSA_SelectOp : WasmSSA_Op<"select", [
+ AllTypesMatch<["true_value", "false_value", "result"]>,
+ Pure]> {
+ let summary = "Select between two values based on a condition.";
+ let description = [{
+ Returns `true_value` if `condition` is non-zero, `false_value` otherwise.
+ Both operands and the result must share the same Wasm value type.
+
+ Example:
+
+ ```mlir
+ // Returns %a if %cond is non-zero, otherwise %b.
+ %r = wasmssa.select %cond, %a, %b : i32
+ ```
+ }];
+ let arguments = (ins WasmSSA_ValType: $true_value,
+ WasmSSA_ValType: $false_value,
+ I32: $condition);
+ let results = (outs WasmSSA_ValType: $result);
+ let assemblyFormat =
+ "$condition `,` $true_value `,` $false_value attr-dict `:` type($result)";
+}
+
// ---- Numeric ops
class WasmSSA_BinaryNumericalOp<string mnemonic, string summaryStr, string descStr,
diff --git a/mlir/test/Dialect/WasmSSA/custom_parser/select.mlir b/mlir/test/Dialect/WasmSSA/custom_parser/select.mlir
new file mode 100644
index 0000000000000..80ced11c01bc3
--- /dev/null
+++ b/mlir/test/Dialect/WasmSSA/custom_parser/select.mlir
@@ -0,0 +1,37 @@
+// RUN: mlir-opt %s | FileCheck %s
+
+module {
+ wasmssa.func @select_i32(%cond: !wasmssa<local ref to i32>,
+ %a: !wasmssa<local ref to i32>,
+ %b: !wasmssa<local ref to i32>) -> i32 {
+ %0 = wasmssa.local_get %cond : ref to i32
+ %1 = wasmssa.local_get %a : ref to i32
+ %2 = wasmssa.local_get %b : ref to i32
+ %r = wasmssa.select %0, %1, %2 : i32
+ wasmssa.return %r : i32
+ }
+
+ wasmssa.func @select_f64(%cond: !wasmssa<local ref to i32>,
+ %a: !wasmssa<local ref to f64>,
+ %b: !wasmssa<local ref to f64>) -> f64 {
+ %0 = wasmssa.local_get %cond : ref to i32
+ %1 = wasmssa.local_get %a : ref to f64
+ %2 = wasmssa.local_get %b : ref to f64
+ %r = wasmssa.select %0, %1, %2 : f64
+ wasmssa.return %r : f64
+ }
+}
+
+// CHECK-LABEL: wasmssa.func @select_i32(
+// CHECK: %[[COND:.*]] = wasmssa.local_get
+// CHECK: %[[A:.*]] = wasmssa.local_get
+// CHECK: %[[B:.*]] = wasmssa.local_get
+// CHECK: %[[R:.*]] = wasmssa.select %[[COND]], %[[A]], %[[B]] : i32
+// CHECK: wasmssa.return %[[R]] : i32
+
+// CHECK-LABEL: wasmssa.func @select_f64(
+// CHECK: %[[COND:.*]] = wasmssa.local_get
+// CHECK: %[[A:.*]] = wasmssa.local_get
+// CHECK: %[[B:.*]] = wasmssa.local_get
+// CHECK: %[[R:.*]] = wasmssa.select %[[COND]], %[[A]], %[[B]] : f64
+// CHECK: wasmssa.return %[[R]] : f64
More information about the Mlir-commits
mailing list