[llvm] [WebAssembly] MC support for acquire-release atomics (PR #183656)
Derek Schuff via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 3 16:50:01 PST 2026
https://github.com/dschuff updated https://github.com/llvm/llvm-project/pull/183656
>From 514164a1d52cf4f27f6c0166aa3036e476cfa867 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 13 Feb 2026 22:09:36 +0000
Subject: [PATCH 01/22] first attempt at MC layer
---
.../AsmParser/WebAssemblyAsmParser.cpp | 305 +++++++++++++++++-
.../MCTargetDesc/WebAssemblyInstPrinter.cpp | 25 ++
.../MCTargetDesc/WebAssemblyInstPrinter.h | 2 +
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 1 +
.../MCTargetDesc/WebAssemblyMCTargetDesc.h | 10 +
.../WebAssembly/WebAssemblyInstrAtomics.td | 115 ++++---
.../WebAssembly/WebAssemblyInstrInfo.td | 6 +
llvm/test/MC/WebAssembly/atomics-encodings.s | 128 ++++----
8 files changed, 490 insertions(+), 102 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 9175b2731dac0..ff60085a2f317 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -472,6 +472,25 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return false;
}
+ bool parseMemOrderMaybe(OperandVector &Operands) {
+ auto &Tok = Lexer.getTok();
+ if (Tok.isNot(AsmToken::Identifier))
+ return false;
+ StringRef S = Tok.getString();
+ int64_t Order = StringSwitch<int64_t>(S)
+ .Case("acquire", WebAssembly::MEM_ORDER_ACQUIRE)
+ .Case("release", WebAssembly::MEM_ORDER_RELEASE)
+ .Case("acq_rel", WebAssembly::MEM_ORDER_ACQ_REL)
+ .Case("seq_cst", WebAssembly::MEM_ORDER_SEQ_CST)
+ .Default(-1);
+ if (Order == -1)
+ return false;
+ Operands.push_back(std::make_unique<WebAssemblyOperand>(
+ Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{Order}));
+ Parser.Lex();
+ return true;
+ }
+
bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {
// FIXME: there is probably a cleaner way to do this.
auto IsLoadStore = InstName.contains(".load") ||
@@ -504,6 +523,14 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
Operands.push_back(std::make_unique<WebAssemblyOperand>(
Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
}
+ if (IsAtomic && !InstName.contains("fence") &&
+ !InstName.contains("notify") && !InstName.contains("wait")) {
+ if (!parseMemOrderMaybe(Operands)) {
+ auto Tok = Lexer.getTok();
+ Operands.push_back(std::make_unique<WebAssemblyOperand>(
+ Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
+ }
+ }
}
return false;
}
@@ -650,6 +677,12 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
} else if (Name == "delegate") {
if (pop(Name, Try))
return true;
+ } else if (Name == "atomic.fence") {
+ if (!parseMemOrderMaybe(Operands)) {
+ auto Tok = Lexer.getTok();
+ Operands.push_back(std::make_unique<WebAssemblyOperand>(
+ Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
+ }
} else if (Name == "end_loop") {
if (pop(Name, Loop))
return true;
@@ -1154,6 +1187,268 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
}
}
+bool isAtomic(unsigned Opc) {
+ switch (Opc) {
+ case WebAssembly::ATOMIC_FENCE:
+ case WebAssembly::ATOMIC_FENCE_S:
+ case WebAssembly::ATOMIC_LOAD16_U_I32_A32:
+ case WebAssembly::ATOMIC_LOAD16_U_I32_A32_S:
+ case WebAssembly::ATOMIC_LOAD16_U_I32_A64:
+ case WebAssembly::ATOMIC_LOAD16_U_I32_A64_S:
+ case WebAssembly::ATOMIC_LOAD16_U_I64_A32:
+ case WebAssembly::ATOMIC_LOAD16_U_I64_A32_S:
+ case WebAssembly::ATOMIC_LOAD16_U_I64_A64:
+ case WebAssembly::ATOMIC_LOAD16_U_I64_A64_S:
+ case WebAssembly::ATOMIC_LOAD32_U_I64_A32:
+ case WebAssembly::ATOMIC_LOAD32_U_I64_A32_S:
+ case WebAssembly::ATOMIC_LOAD32_U_I64_A64:
+ case WebAssembly::ATOMIC_LOAD32_U_I64_A64_S:
+ case WebAssembly::ATOMIC_LOAD8_U_I32_A32:
+ case WebAssembly::ATOMIC_LOAD8_U_I32_A32_S:
+ case WebAssembly::ATOMIC_LOAD8_U_I32_A64:
+ case WebAssembly::ATOMIC_LOAD8_U_I32_A64_S:
+ case WebAssembly::ATOMIC_LOAD8_U_I64_A32:
+ case WebAssembly::ATOMIC_LOAD8_U_I64_A32_S:
+ case WebAssembly::ATOMIC_LOAD8_U_I64_A64:
+ case WebAssembly::ATOMIC_LOAD8_U_I64_A64_S:
+ case WebAssembly::ATOMIC_LOAD_I32_A32:
+ case WebAssembly::ATOMIC_LOAD_I32_A32_S:
+ case WebAssembly::ATOMIC_LOAD_I32_A64:
+ case WebAssembly::ATOMIC_LOAD_I32_A64_S:
+ case WebAssembly::ATOMIC_LOAD_I64_A32:
+ case WebAssembly::ATOMIC_LOAD_I64_A32_S:
+ case WebAssembly::ATOMIC_LOAD_I64_A64:
+ case WebAssembly::ATOMIC_LOAD_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_ADD_I32_A32:
+ case WebAssembly::ATOMIC_RMW16_U_ADD_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_ADD_I32_A64:
+ case WebAssembly::ATOMIC_RMW16_U_ADD_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_ADD_I64_A32:
+ case WebAssembly::ATOMIC_RMW16_U_ADD_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_ADD_I64_A64:
+ case WebAssembly::ATOMIC_RMW16_U_ADD_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_AND_I32_A32:
+ case WebAssembly::ATOMIC_RMW16_U_AND_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_AND_I32_A64:
+ case WebAssembly::ATOMIC_RMW16_U_AND_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_AND_I64_A32:
+ case WebAssembly::ATOMIC_RMW16_U_AND_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_AND_I64_A64:
+ case WebAssembly::ATOMIC_RMW16_U_AND_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I32_A32:
+ case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I32_A64:
+ case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I64_A32:
+ case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I64_A64:
+ case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_OR_I32_A32:
+ case WebAssembly::ATOMIC_RMW16_U_OR_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_OR_I32_A64:
+ case WebAssembly::ATOMIC_RMW16_U_OR_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_OR_I64_A32:
+ case WebAssembly::ATOMIC_RMW16_U_OR_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_OR_I64_A64:
+ case WebAssembly::ATOMIC_RMW16_U_OR_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_SUB_I32_A32:
+ case WebAssembly::ATOMIC_RMW16_U_SUB_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_SUB_I32_A64:
+ case WebAssembly::ATOMIC_RMW16_U_SUB_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_SUB_I64_A32:
+ case WebAssembly::ATOMIC_RMW16_U_SUB_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_SUB_I64_A64:
+ case WebAssembly::ATOMIC_RMW16_U_SUB_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_XCHG_I32_A32:
+ case WebAssembly::ATOMIC_RMW16_U_XCHG_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_XCHG_I32_A64:
+ case WebAssembly::ATOMIC_RMW16_U_XCHG_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_XCHG_I64_A32:
+ case WebAssembly::ATOMIC_RMW16_U_XCHG_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_XCHG_I64_A64:
+ case WebAssembly::ATOMIC_RMW16_U_XCHG_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_XOR_I32_A32:
+ case WebAssembly::ATOMIC_RMW16_U_XOR_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_XOR_I32_A64:
+ case WebAssembly::ATOMIC_RMW16_U_XOR_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW16_U_XOR_I64_A32:
+ case WebAssembly::ATOMIC_RMW16_U_XOR_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW16_U_XOR_I64_A64:
+ case WebAssembly::ATOMIC_RMW16_U_XOR_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW32_U_ADD_I64_A32:
+ case WebAssembly::ATOMIC_RMW32_U_ADD_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW32_U_ADD_I64_A64:
+ case WebAssembly::ATOMIC_RMW32_U_ADD_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW32_U_AND_I64_A32:
+ case WebAssembly::ATOMIC_RMW32_U_AND_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW32_U_AND_I64_A64:
+ case WebAssembly::ATOMIC_RMW32_U_AND_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW32_U_CMPXCHG_I64_A32:
+ case WebAssembly::ATOMIC_RMW32_U_CMPXCHG_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW32_U_CMPXCHG_I64_A64:
+ case WebAssembly::ATOMIC_RMW32_U_CMPXCHG_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW32_U_OR_I64_A32:
+ case WebAssembly::ATOMIC_RMW32_U_OR_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW32_U_OR_I64_A64:
+ case WebAssembly::ATOMIC_RMW32_U_OR_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW32_U_SUB_I64_A32:
+ case WebAssembly::ATOMIC_RMW32_U_SUB_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW32_U_SUB_I64_A64:
+ case WebAssembly::ATOMIC_RMW32_U_SUB_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW32_U_XCHG_I64_A32:
+ case WebAssembly::ATOMIC_RMW32_U_XCHG_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW32_U_XCHG_I64_A64:
+ case WebAssembly::ATOMIC_RMW32_U_XCHG_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW32_U_XOR_I64_A32:
+ case WebAssembly::ATOMIC_RMW32_U_XOR_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW32_U_XOR_I64_A64:
+ case WebAssembly::ATOMIC_RMW32_U_XOR_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_ADD_I32_A32:
+ case WebAssembly::ATOMIC_RMW8_U_ADD_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_ADD_I32_A64:
+ case WebAssembly::ATOMIC_RMW8_U_ADD_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_ADD_I64_A32:
+ case WebAssembly::ATOMIC_RMW8_U_ADD_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_ADD_I64_A64:
+ case WebAssembly::ATOMIC_RMW8_U_ADD_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_AND_I32_A32:
+ case WebAssembly::ATOMIC_RMW8_U_AND_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_AND_I32_A64:
+ case WebAssembly::ATOMIC_RMW8_U_AND_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_AND_I64_A32:
+ case WebAssembly::ATOMIC_RMW8_U_AND_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_AND_I64_A64:
+ case WebAssembly::ATOMIC_RMW8_U_AND_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I32_A32:
+ case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I32_A64:
+ case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I64_A32:
+ case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I64_A64:
+ case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_OR_I32_A32:
+ case WebAssembly::ATOMIC_RMW8_U_OR_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_OR_I32_A64:
+ case WebAssembly::ATOMIC_RMW8_U_OR_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_OR_I64_A32:
+ case WebAssembly::ATOMIC_RMW8_U_OR_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_OR_I64_A64:
+ case WebAssembly::ATOMIC_RMW8_U_OR_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_SUB_I32_A32:
+ case WebAssembly::ATOMIC_RMW8_U_SUB_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_SUB_I32_A64:
+ case WebAssembly::ATOMIC_RMW8_U_SUB_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_SUB_I64_A32:
+ case WebAssembly::ATOMIC_RMW8_U_SUB_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_SUB_I64_A64:
+ case WebAssembly::ATOMIC_RMW8_U_SUB_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_XCHG_I32_A32:
+ case WebAssembly::ATOMIC_RMW8_U_XCHG_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_XCHG_I32_A64:
+ case WebAssembly::ATOMIC_RMW8_U_XCHG_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_XCHG_I64_A32:
+ case WebAssembly::ATOMIC_RMW8_U_XCHG_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_XCHG_I64_A64:
+ case WebAssembly::ATOMIC_RMW8_U_XCHG_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_XOR_I32_A32:
+ case WebAssembly::ATOMIC_RMW8_U_XOR_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_XOR_I32_A64:
+ case WebAssembly::ATOMIC_RMW8_U_XOR_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW8_U_XOR_I64_A32:
+ case WebAssembly::ATOMIC_RMW8_U_XOR_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW8_U_XOR_I64_A64:
+ case WebAssembly::ATOMIC_RMW8_U_XOR_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW_ADD_I32_A32:
+ case WebAssembly::ATOMIC_RMW_ADD_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW_ADD_I32_A64:
+ case WebAssembly::ATOMIC_RMW_ADD_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW_ADD_I64_A32:
+ case WebAssembly::ATOMIC_RMW_ADD_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW_ADD_I64_A64:
+ case WebAssembly::ATOMIC_RMW_ADD_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW_AND_I32_A32:
+ case WebAssembly::ATOMIC_RMW_AND_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW_AND_I32_A64:
+ case WebAssembly::ATOMIC_RMW_AND_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW_AND_I64_A32:
+ case WebAssembly::ATOMIC_RMW_AND_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW_AND_I64_A64:
+ case WebAssembly::ATOMIC_RMW_AND_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW_CMPXCHG_I32_A32:
+ case WebAssembly::ATOMIC_RMW_CMPXCHG_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW_CMPXCHG_I32_A64:
+ case WebAssembly::ATOMIC_RMW_CMPXCHG_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW_CMPXCHG_I64_A32:
+ case WebAssembly::ATOMIC_RMW_CMPXCHG_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW_CMPXCHG_I64_A64:
+ case WebAssembly::ATOMIC_RMW_CMPXCHG_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW_OR_I32_A32:
+ case WebAssembly::ATOMIC_RMW_OR_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW_OR_I32_A64:
+ case WebAssembly::ATOMIC_RMW_OR_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW_OR_I64_A32:
+ case WebAssembly::ATOMIC_RMW_OR_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW_OR_I64_A64:
+ case WebAssembly::ATOMIC_RMW_OR_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW_SUB_I32_A32:
+ case WebAssembly::ATOMIC_RMW_SUB_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW_SUB_I32_A64:
+ case WebAssembly::ATOMIC_RMW_SUB_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW_SUB_I64_A32:
+ case WebAssembly::ATOMIC_RMW_SUB_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW_SUB_I64_A64:
+ case WebAssembly::ATOMIC_RMW_SUB_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW_XCHG_I32_A32:
+ case WebAssembly::ATOMIC_RMW_XCHG_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW_XCHG_I32_A64:
+ case WebAssembly::ATOMIC_RMW_XCHG_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW_XCHG_I64_A32:
+ case WebAssembly::ATOMIC_RMW_XCHG_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW_XCHG_I64_A64:
+ case WebAssembly::ATOMIC_RMW_XCHG_I64_A64_S:
+ case WebAssembly::ATOMIC_RMW_XOR_I32_A32:
+ case WebAssembly::ATOMIC_RMW_XOR_I32_A32_S:
+ case WebAssembly::ATOMIC_RMW_XOR_I32_A64:
+ case WebAssembly::ATOMIC_RMW_XOR_I32_A64_S:
+ case WebAssembly::ATOMIC_RMW_XOR_I64_A32:
+ case WebAssembly::ATOMIC_RMW_XOR_I64_A32_S:
+ case WebAssembly::ATOMIC_RMW_XOR_I64_A64:
+ case WebAssembly::ATOMIC_RMW_XOR_I64_A64_S:
+ case WebAssembly::ATOMIC_STORE16_I32_A32:
+ case WebAssembly::ATOMIC_STORE16_I32_A32_S:
+ case WebAssembly::ATOMIC_STORE16_I32_A64:
+ case WebAssembly::ATOMIC_STORE16_I32_A64_S:
+ case WebAssembly::ATOMIC_STORE16_I64_A32:
+ case WebAssembly::ATOMIC_STORE16_I64_A32_S:
+ case WebAssembly::ATOMIC_STORE16_I64_A64:
+ case WebAssembly::ATOMIC_STORE16_I64_A64_S:
+ case WebAssembly::ATOMIC_STORE32_I64_A32:
+ case WebAssembly::ATOMIC_STORE32_I64_A32_S:
+ case WebAssembly::ATOMIC_STORE32_I64_A64:
+ case WebAssembly::ATOMIC_STORE32_I64_A64_S:
+ case WebAssembly::ATOMIC_STORE8_I32_A32:
+ case WebAssembly::ATOMIC_STORE8_I32_A32_S:
+ case WebAssembly::ATOMIC_STORE8_I32_A64:
+ case WebAssembly::ATOMIC_STORE8_I32_A64_S:
+ case WebAssembly::ATOMIC_STORE8_I64_A32:
+ case WebAssembly::ATOMIC_STORE8_I64_A32_S:
+ case WebAssembly::ATOMIC_STORE8_I64_A64:
+ case WebAssembly::ATOMIC_STORE8_I64_A64_S:
+ case WebAssembly::ATOMIC_STORE_I32_A32:
+ case WebAssembly::ATOMIC_STORE_I32_A32_S:
+ case WebAssembly::ATOMIC_STORE_I32_A64:
+ case WebAssembly::ATOMIC_STORE_I32_A64_S:
+ case WebAssembly::ATOMIC_STORE_I64_A32:
+ case WebAssembly::ATOMIC_STORE_I64_A32_S:
+ case WebAssembly::ATOMIC_STORE_I64_A64:
+ case WebAssembly::ATOMIC_STORE_I64_A64_S:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool matchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
OperandVector &Operands, MCStreamer &Out,
uint64_t &ErrorInfo,
@@ -1170,7 +1465,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode());
if (Align != -1U) {
auto &Op0 = Inst.getOperand(0);
- if (Op0.getImm() == -1)
+ if (Op0.isImm() && Op0.getImm() == -1)
Op0.setImm(Align);
}
if (Is64) {
@@ -1183,6 +1478,14 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
Inst.setOpcode(Opc64);
}
}
+ // Fix unknown memory ordering operands.
+ if (isAtomic(Inst.getOpcode())) {
+ for (unsigned i = 0; i < Inst.getNumOperands(); ++i) {
+ auto &Op = Inst.getOperand(i);
+ if (Op.isImm() && Op.getImm() == -1)
+ Op.setImm(WebAssembly::MEM_ORDER_SEQ_CST);
+ }
+ }
if (!SkipTypeCheck)
TC.typeCheck(IDLoc, Inst, Operands);
Out.emitInstruction(Inst, getSTI());
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 651f631c1ee55..a3730f9a3202c 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -370,6 +370,31 @@ void WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand(const MCInst *MI,
O << ":p2align=" << Imm;
}
+void WebAssemblyInstPrinter::printWebAssemblyMemOrderOperand(const MCInst *MI,
+ unsigned OpNo,
+ raw_ostream &O) {
+ int64_t Imm = MI->getOperand(OpNo).getImm();
+ switch (Imm) {
+ case WebAssembly::MEM_ORDER_NONE:
+ // none is the default, print nothing
+ return;
+ case WebAssembly::MEM_ORDER_ACQUIRE:
+ O << " acquire";
+ break;
+ case WebAssembly::MEM_ORDER_RELEASE:
+ O << " release";
+ break;
+ case WebAssembly::MEM_ORDER_ACQ_REL:
+ O << " acq_rel";
+ break;
+ case WebAssembly::MEM_ORDER_SEQ_CST:
+ O << " seq_cst";
+ break;
+ default:
+ llvm_unreachable("Unknown memory ordering");
+ }
+}
+
void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI,
unsigned OpNo,
raw_ostream &O) {
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
index c9351a0e44926..7181641c81b3c 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
@@ -45,6 +45,8 @@ class WebAssemblyInstPrinter final : public MCInstPrinter {
void printBrList(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printWebAssemblyP2AlignOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O);
+ void printWebAssemblyMemOrderOperand(const MCInst *MI, unsigned OpNo,
+ raw_ostream &O);
void printWebAssemblySignatureOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O);
void printCatchList(const MCInst *MI, unsigned OpNo, raw_ostream &O);
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 70961041d7a8e..1de64ed142a1e 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -111,6 +111,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
break;
case WebAssembly::OPERAND_SIGNATURE:
case WebAssembly::OPERAND_VEC_I8IMM:
+ case WebAssembly::OPERAND_MEMORDER:
support::endian::write<uint8_t>(OS, MO.getImm(),
llvm::endianness::little);
break;
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
index 5dc0e3aa91622..59b152251e053 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
@@ -82,6 +82,16 @@ enum OperandType {
OPERAND_TABLE,
/// A list of catch clauses for try_table.
OPERAND_CATCH_LIST,
+ /// memory ordering immediate for atomic instructions.
+ OPERAND_MEMORDER,
+};
+
+enum MemOrder {
+ MEM_ORDER_NONE = 0,
+ MEM_ORDER_ACQUIRE = 1,
+ MEM_ORDER_RELEASE = 2,
+ MEM_ORDER_ACQ_REL = 3,
+ MEM_ORDER_SEQ_CST = 4,
};
} // end namespace WebAssembly
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
index e9693e7141efd..b8228e27c841d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
@@ -110,25 +110,50 @@ let Defs = [ARGUMENTS] in {
let isPseudo = 1, hasSideEffects = 1 in
defm COMPILER_FENCE : ATOMIC_NRI<(outs), (ins), [], "compiler_fence">;
let hasSideEffects = 1 in
-defm ATOMIC_FENCE : ATOMIC_NRI<(outs), (ins i8imm:$flags), [], "atomic.fence",
- 0x03>;
+defm ATOMIC_FENCE : ATOMIC_NRI<(outs), (ins MemOrder:$order), [],
+ "atomic.fence${order}", 0x03>;
} // Defs = [ARGUMENTS]
//===----------------------------------------------------------------------===//
// Atomic loads
//===----------------------------------------------------------------------===//
+multiclass WebAssemblyAtomicLoad<WebAssemblyRegClass rc, string name, int Opcode> {
+ let mayLoad = 1, UseNamedOperandTable = 1 in {
+ defm "_A32": I<(outs rc:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr),
+ (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order),
+ [], !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}"),
+ !strconcat(name, "\t${off}${p2align}${order}"), Opcode, false>,
+ Requires<[HasAtomics]>;
+ defm "_A64": I<(outs rc:$dst),
+ (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr),
+ (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order),
+ [], !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}"),
+ !strconcat(name, "\t${off}${p2align}${order}"), Opcode, true>,
+ Requires<[HasAtomics]>;
+ }
+}
+
multiclass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> {
- defm "" : WebAssemblyLoad<rc, name, !or(0xfe00, !and(0xff, atomic_op)),
- [HasAtomics]>;
+ defm "" : WebAssemblyAtomicLoad<rc, name, !or(0xfe00, !and(0xff, atomic_op))>;
+}
+
+multiclass AtomicLoadPat<ValueType ty, SDPatternOperator kind, string Name> {
+ def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr))),
+ (!cast<NI>(Name # "_A32") 0, offset32_op:$offset, 4, I32:$addr)>,
+ Requires<[HasAddr32, HasAtomics]>;
+ def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr))),
+ (!cast<NI>(Name # "_A64") 0, offset64_op:$offset, 4, I64:$addr)>,
+ Requires<[HasAddr64, HasAtomics]>;
}
defm ATOMIC_LOAD_I32 : AtomicLoad<I32, "i32.atomic.load", 0x10>;
defm ATOMIC_LOAD_I64 : AtomicLoad<I64, "i64.atomic.load", 0x11>;
// Select loads
-defm : LoadPat<i32, atomic_load_nonext_32, "ATOMIC_LOAD_I32">;
-defm : LoadPat<i64, atomic_load_nonext_64, "ATOMIC_LOAD_I64">;
+defm : AtomicLoadPat<i32, atomic_load_nonext_32, "ATOMIC_LOAD_I32">;
+defm : AtomicLoadPat<i64, atomic_load_nonext_64, "ATOMIC_LOAD_I64">;
// Extending loads. Note that there are only zero-extending atomic loads, no
// sign-extending loads.
@@ -168,15 +193,15 @@ def sext_aload_16_64 :
PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_azext_16 node:$addr)))>;
// Select zero-extending loads
-defm : LoadPat<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
-defm : LoadPat<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
-defm : LoadPat<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">;
+defm : AtomicLoadPat<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
+defm : AtomicLoadPat<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
+defm : AtomicLoadPat<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">;
// Select sign-extending loads
-defm : LoadPat<i32, atomic_load_zext_8, "ATOMIC_LOAD8_U_I32">;
-defm : LoadPat<i32, atomic_load_zext_16, "ATOMIC_LOAD16_U_I32">;
-defm : LoadPat<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
-defm : LoadPat<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
+defm : AtomicLoadPat<i32, atomic_load_zext_8, "ATOMIC_LOAD8_U_I32">;
+defm : AtomicLoadPat<i32, atomic_load_zext_16, "ATOMIC_LOAD16_U_I32">;
+defm : AtomicLoadPat<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
+defm : AtomicLoadPat<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
// 32->64 sext load gets selected as i32.atomic.load, i64.extend_i32_s
@@ -184,9 +209,25 @@ defm : LoadPat<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
// Atomic stores
//===----------------------------------------------------------------------===//
+multiclass WebAssemblyAtomicStore<WebAssemblyRegClass rc, string name, int Opcode> {
+ let mayStore = 1, UseNamedOperandTable = 1 in {
+ defm "_A32" : I<(outs),
+ (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, rc:$val),
+ (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ !strconcat(name, "\t${off}(${addr})${p2align}${order}, $val"),
+ !strconcat(name, "\t${off}${p2align}${order}"), Opcode, false>,
+ Requires<[HasAtomics]>;
+ defm "_A64" : I<(outs),
+ (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, rc:$val),
+ (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ !strconcat(name, "\t${off}(${addr})${p2align}${order}, $val"),
+ !strconcat(name, "\t${off}${p2align}${order}"), Opcode, true>,
+ Requires<[HasAtomics]>;
+ }
+}
+
multiclass AtomicStore<WebAssemblyRegClass rc, string name, int atomic_op> {
- defm "" : WebAssemblyStore<rc, name, !or(0xfe00, !and(0xff, atomic_op)),
- [HasAtomics]>;
+ defm "" : WebAssemblyAtomicStore<rc, name, !or(0xfe00, !and(0xff, atomic_op))>;
}
defm ATOMIC_STORE_I32 : AtomicStore<I32, "i32.atomic.store", 0x17>;
@@ -200,10 +241,10 @@ defm ATOMIC_STORE_I64 : AtomicStore<I64, "i64.atomic.store", 0x18>;
multiclass AStorePat<ValueType ty, PatFrag kind, string inst> {
def : Pat<(kind ty:$val, (AddrOps32 offset32_op:$offset, I32:$addr)),
- (!cast<NI>(inst#_A32) 0, $offset, $addr, $val)>,
+ (!cast<NI>(inst#_A32) 0, $offset, 4, $addr, $val)>,
Requires<[HasAddr32, HasAtomics]>;
def : Pat<(kind ty:$val, (AddrOps64 offset64_op:$offset, I64:$addr)),
- (!cast<NI>(inst#_A64) 0, $offset, $addr, $val)>,
+ (!cast<NI>(inst#_A64) 0, $offset, 4, $addr, $val)>,
Requires<[HasAddr64, HasAtomics]>;
}
defm : AStorePat<i32, atomic_store_32, "ATOMIC_STORE_I32">;
@@ -243,16 +284,16 @@ multiclass WebAssemblyBinRMW<WebAssemblyRegClass rc, string name,
int atomic_op> {
defm "_A32" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
- (outs), (ins P2Align:$p2align, offset32_op:$off), [],
- !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"),
- !strconcat(name, "\t${off}${p2align}"), atomic_op, false>;
+ (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, rc:$val),
+ (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $val"),
+ !strconcat(name, "\t${off}${p2align}${order}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val),
- (outs), (ins P2Align:$p2align, offset64_op:$off), [],
- !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"),
- !strconcat(name, "\t${off}${p2align}"), atomic_op, true>;
+ (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, rc:$val),
+ (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $val"),
+ !strconcat(name, "\t${off}${p2align}${order}"), atomic_op, true>;
}
defm ATOMIC_RMW_ADD_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.add", 0x1e>;
@@ -337,10 +378,10 @@ defm ATOMIC_RMW32_U_XCHG_I64 :
multiclass BinRMWPat<ValueType ty, PatFrag kind, string inst> {
def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$val)),
- (!cast<NI>(inst#_A32) 0, $offset, $addr, $val)>,
+ (!cast<NI>(inst#_A32) 0, $offset, 4, $addr, $val)>,
Requires<[HasAddr32, HasAtomics]>;
def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$val)),
- (!cast<NI>(inst#_A64) 0, $offset, $addr, $val)>,
+ (!cast<NI>(inst#_A64) 0, $offset, 4, $addr, $val)>,
Requires<[HasAddr64, HasAtomics]>;
}
@@ -447,18 +488,18 @@ multiclass WebAssemblyTerRMW<WebAssemblyRegClass rc, string name,
int atomic_op> {
defm "_A32" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$exp,
+ (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, rc:$exp,
rc:$new_),
- (outs), (ins P2Align:$p2align, offset32_op:$off), [],
- !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"),
- !strconcat(name, "\t${off}${p2align}"), atomic_op, false>;
+ (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $exp, $new_"),
+ !strconcat(name, "\t${off}${p2align}${order}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$exp,
+ (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, rc:$exp,
rc:$new_),
- (outs), (ins P2Align:$p2align, offset64_op:$off), [],
- !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"),
- !strconcat(name, "\t${off}${p2align}"), atomic_op, true>;
+ (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $exp, $new_"),
+ !strconcat(name, "\t${off}${p2align}${order}"), atomic_op, true>;
}
defm ATOMIC_RMW_CMPXCHG_I32 :
@@ -478,10 +519,10 @@ defm ATOMIC_RMW32_U_CMPXCHG_I64 :
multiclass TerRMWPat<ValueType ty, PatFrag kind, string inst> {
def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$exp, ty:$new)),
- (!cast<NI>(inst#_A32) 0, $offset, $addr, $exp, $new)>,
+ (!cast<NI>(inst#_A32) 0, $offset, 4, $addr, $exp, $new)>,
Requires<[HasAddr32, HasAtomics]>;
def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$exp, ty:$new)),
- (!cast<NI>(inst#_A64) 0, $offset, $addr, $exp, $new)>,
+ (!cast<NI>(inst#_A64) 0, $offset, 4, $addr, $exp, $new)>,
Requires<[HasAddr64, HasAtomics]>;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 76e94c2ec3d61..083b85582aa75 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -230,6 +230,12 @@ def tag_op : Operand<i32>;
} // OperandType = "OPERAND_P2ALIGN"
+let OperandType = "OPERAND_MEMORDER" in {
+def MemOrder : Operand<i32> {
+ let PrintMethod = "printWebAssemblyMemOrderOperand";
+}
+} // OperandType = "OPERAND_MEMORDER"
+
let OperandType = "OPERAND_SIGNATURE" in
def Signature : Operand<i32> {
let PrintMethod = "printWebAssemblySignatureOperand";
diff --git a/llvm/test/MC/WebAssembly/atomics-encodings.s b/llvm/test/MC/WebAssembly/atomics-encodings.s
index aa0117d623e45..f7899b5f5e5d9 100644
--- a/llvm/test/MC/WebAssembly/atomics-encodings.s
+++ b/llvm/test/MC/WebAssembly/atomics-encodings.s
@@ -10,142 +10,142 @@ main:
# CHECK: memory.atomic.wait64 0 # encoding: [0xfe,0x02,0x03,0x00]
memory.atomic.wait64 0
- # CHECK: atomic.fence # encoding: [0xfe,0x03,0x00]
+ # CHECK: atomic.fence seq_cst # encoding: [0xfe,0x03,0x04]
atomic.fence
- # CHECK: i32.atomic.load 0 # encoding: [0xfe,0x10,0x02,0x00]
+ # CHECK: i32.atomic.load 0 seq_cst # encoding: [0xfe,0x10,0x02,0x00,0x04]
i32.atomic.load 0
- # CHECK: i64.atomic.load 4 # encoding: [0xfe,0x11,0x03,0x04]
+ # CHECK: i64.atomic.load 4 seq_cst # encoding: [0xfe,0x11,0x03,0x04,0x04]
i64.atomic.load 4
- # CHECK: i32.atomic.load8_u 48 # encoding: [0xfe,0x12,0x00,0x30]
+ # CHECK: i32.atomic.load8_u 48 seq_cst # encoding: [0xfe,0x12,0x00,0x30,0x04]
i32.atomic.load8_u 48
- # CHECK: i32.atomic.load16_u 0 # encoding: [0xfe,0x13,0x01,0x00]
+ # CHECK: i32.atomic.load16_u 0 seq_cst # encoding: [0xfe,0x13,0x01,0x00,0x04]
i32.atomic.load16_u 0
- # CHECK: i64.atomic.load8_u 0 # encoding: [0xfe,0x14,0x00,0x00]
+ # CHECK: i64.atomic.load8_u 0 seq_cst # encoding: [0xfe,0x14,0x00,0x00,0x04]
i64.atomic.load8_u 0
- # CHECK: i64.atomic.load16_u 0 # encoding: [0xfe,0x15,0x01,0x00]
+ # CHECK: i64.atomic.load16_u 0 seq_cst # encoding: [0xfe,0x15,0x01,0x00,0x04]
i64.atomic.load16_u 0
- # CHECK: i64.atomic.load32_u 0 # encoding: [0xfe,0x16,0x02,0x00]
+ # CHECK: i64.atomic.load32_u 0 seq_cst # encoding: [0xfe,0x16,0x02,0x00,0x04]
i64.atomic.load32_u 0
- # CHECK: i32.atomic.store 0 # encoding: [0xfe,0x17,0x02,0x00]
+ # CHECK: i32.atomic.store 0 seq_cst # encoding: [0xfe,0x17,0x02,0x00,0x04]
i32.atomic.store 0
- # CHECK: i64.atomic.store 8 # encoding: [0xfe,0x18,0x03,0x08]
+ # CHECK: i64.atomic.store 8 seq_cst # encoding: [0xfe,0x18,0x03,0x08,0x04]
i64.atomic.store 8
- # CHECK: i32.atomic.store8 0 # encoding: [0xfe,0x19,0x00,0x00]
+ # CHECK: i32.atomic.store8 0 seq_cst # encoding: [0xfe,0x19,0x00,0x00,0x04]
i32.atomic.store8 0
- # CHECK: i32.atomic.store16 0 # encoding: [0xfe,0x1a,0x01,0x00]
+ # CHECK: i32.atomic.store16 0 seq_cst # encoding: [0xfe,0x1a,0x01,0x00,0x04]
i32.atomic.store16 0
- # CHECK: i64.atomic.store8 16 # encoding: [0xfe,0x1b,0x00,0x10]
+ # CHECK: i64.atomic.store8 16 seq_cst # encoding: [0xfe,0x1b,0x00,0x10,0x04]
i64.atomic.store8 16
- # CHECK: i64.atomic.store16 0 # encoding: [0xfe,0x1c,0x01,0x00]
+ # CHECK: i64.atomic.store16 0 seq_cst # encoding: [0xfe,0x1c,0x01,0x00,0x04]
i64.atomic.store16 0
- # CHECK: i64.atomic.store32 0 # encoding: [0xfe,0x1d,0x02,0x00]
+ # CHECK: i64.atomic.store32 0 seq_cst # encoding: [0xfe,0x1d,0x02,0x00,0x04]
i64.atomic.store32 0
- # CHECK: i32.atomic.rmw.add 0 # encoding: [0xfe,0x1e,0x02,0x00]
+ # CHECK: i32.atomic.rmw.add 0 seq_cst # encoding: [0xfe,0x1e,0x02,0x00,0x04]
i32.atomic.rmw.add 0
- # CHECK: i64.atomic.rmw.add 0 # encoding: [0xfe,0x1f,0x03,0x00]
+ # CHECK: i64.atomic.rmw.add 0 seq_cst # encoding: [0xfe,0x1f,0x03,0x00,0x04]
i64.atomic.rmw.add 0
- # CHECK: i32.atomic.rmw8.add_u 0 # encoding: [0xfe,0x20,0x00,0x00]
+ # CHECK: i32.atomic.rmw8.add_u 0 seq_cst # encoding: [0xfe,0x20,0x00,0x00,0x04]
i32.atomic.rmw8.add_u 0
- # CHECK: i32.atomic.rmw16.add_u 0 # encoding: [0xfe,0x21,0x01,0x00]
+ # CHECK: i32.atomic.rmw16.add_u 0 seq_cst # encoding: [0xfe,0x21,0x01,0x00,0x04]
i32.atomic.rmw16.add_u 0
- # CHECK: i64.atomic.rmw8.add_u 0 # encoding: [0xfe,0x22,0x00,0x00]
+ # CHECK: i64.atomic.rmw8.add_u 0 seq_cst # encoding: [0xfe,0x22,0x00,0x00,0x04]
i64.atomic.rmw8.add_u 0
- # CHECK: i64.atomic.rmw16.add_u 0 # encoding: [0xfe,0x23,0x01,0x00]
+ # CHECK: i64.atomic.rmw16.add_u 0 seq_cst # encoding: [0xfe,0x23,0x01,0x00,0x04]
i64.atomic.rmw16.add_u 0
- # CHECK: i64.atomic.rmw32.add_u 16 # encoding: [0xfe,0x24,0x02,0x10]
+ # CHECK: i64.atomic.rmw32.add_u 16 seq_cst # encoding: [0xfe,0x24,0x02,0x10,0x04]
i64.atomic.rmw32.add_u 16
- # CHECK: i32.atomic.rmw.sub 0 # encoding: [0xfe,0x25,0x02,0x00]
+ # CHECK: i32.atomic.rmw.sub 0 seq_cst # encoding: [0xfe,0x25,0x02,0x00,0x04]
i32.atomic.rmw.sub 0
- # CHECK: i64.atomic.rmw.sub 0 # encoding: [0xfe,0x26,0x03,0x00]
+ # CHECK: i64.atomic.rmw.sub 0 seq_cst # encoding: [0xfe,0x26,0x03,0x00,0x04]
i64.atomic.rmw.sub 0
- # CHECK: i32.atomic.rmw8.sub_u 0 # encoding: [0xfe,0x27,0x00,0x00]
+ # CHECK: i32.atomic.rmw8.sub_u 0 seq_cst # encoding: [0xfe,0x27,0x00,0x00,0x04]
i32.atomic.rmw8.sub_u 0
- # CHECK: i32.atomic.rmw16.sub_u 0 # encoding: [0xfe,0x28,0x01,0x00]
+ # CHECK: i32.atomic.rmw16.sub_u 0 seq_cst # encoding: [0xfe,0x28,0x01,0x00,0x04]
i32.atomic.rmw16.sub_u 0
- # CHECK: i64.atomic.rmw8.sub_u 8 # encoding: [0xfe,0x29,0x00,0x08]
+ # CHECK: i64.atomic.rmw8.sub_u 8 seq_cst # encoding: [0xfe,0x29,0x00,0x08,0x04]
i64.atomic.rmw8.sub_u 8
- # CHECK: i64.atomic.rmw16.sub_u 0 # encoding: [0xfe,0x2a,0x01,0x00]
+ # CHECK: i64.atomic.rmw16.sub_u 0 seq_cst # encoding: [0xfe,0x2a,0x01,0x00,0x04]
i64.atomic.rmw16.sub_u 0
- # CHECK: i64.atomic.rmw32.sub_u 0 # encoding: [0xfe,0x2b,0x02,0x00]
+ # CHECK: i64.atomic.rmw32.sub_u 0 seq_cst # encoding: [0xfe,0x2b,0x02,0x00,0x04]
i64.atomic.rmw32.sub_u 0
- # CHECK: i32.atomic.rmw.and 0 # encoding: [0xfe,0x2c,0x02,0x00]
+ # CHECK: i32.atomic.rmw.and 0 seq_cst # encoding: [0xfe,0x2c,0x02,0x00,0x04]
i32.atomic.rmw.and 0
- # CHECK: i64.atomic.rmw.and 0 # encoding: [0xfe,0x2d,0x03,0x00]
+ # CHECK: i64.atomic.rmw.and 0 seq_cst # encoding: [0xfe,0x2d,0x03,0x00,0x04]
i64.atomic.rmw.and 0
- # CHECK: i32.atomic.rmw8.and_u 0 # encoding: [0xfe,0x2e,0x00,0x00]
+ # CHECK: i32.atomic.rmw8.and_u 0 seq_cst # encoding: [0xfe,0x2e,0x00,0x00,0x04]
i32.atomic.rmw8.and_u 0
- # CHECK: i32.atomic.rmw16.and_u 0 # encoding: [0xfe,0x2f,0x01,0x00]
+ # CHECK: i32.atomic.rmw16.and_u 0 seq_cst # encoding: [0xfe,0x2f,0x01,0x00,0x04]
i32.atomic.rmw16.and_u 0
- # CHECK: i64.atomic.rmw8.and_u 96 # encoding: [0xfe,0x30,0x00,0x60]
+ # CHECK: i64.atomic.rmw8.and_u 96 seq_cst # encoding: [0xfe,0x30,0x00,0x60,0x04]
i64.atomic.rmw8.and_u 96
- # CHECK: i64.atomic.rmw16.and_u 0 # encoding: [0xfe,0x31,0x01,0x00]
+ # CHECK: i64.atomic.rmw16.and_u 0 seq_cst # encoding: [0xfe,0x31,0x01,0x00,0x04]
i64.atomic.rmw16.and_u 0
- # CHECK: i64.atomic.rmw32.and_u 0 # encoding: [0xfe,0x32,0x02,0x00]
+ # CHECK: i64.atomic.rmw32.and_u 0 seq_cst # encoding: [0xfe,0x32,0x02,0x00,0x04]
i64.atomic.rmw32.and_u 0
- # CHECK: i32.atomic.rmw.or 0 # encoding: [0xfe,0x33,0x02,0x00]
+ # CHECK: i32.atomic.rmw.or 0 seq_cst # encoding: [0xfe,0x33,0x02,0x00,0x04]
i32.atomic.rmw.or 0
- # CHECK: i64.atomic.rmw.or 0 # encoding: [0xfe,0x34,0x03,0x00]
+ # CHECK: i64.atomic.rmw.or 0 seq_cst # encoding: [0xfe,0x34,0x03,0x00,0x04]
i64.atomic.rmw.or 0
- # CHECK: i32.atomic.rmw8.or_u 0 # encoding: [0xfe,0x35,0x00,0x00]
+ # CHECK: i32.atomic.rmw8.or_u 0 seq_cst # encoding: [0xfe,0x35,0x00,0x00,0x04]
i32.atomic.rmw8.or_u 0
- # CHECK: i32.atomic.rmw16.or_u 0 # encoding: [0xfe,0x36,0x01,0x00]
+ # CHECK: i32.atomic.rmw16.or_u 0 seq_cst # encoding: [0xfe,0x36,0x01,0x00,0x04]
i32.atomic.rmw16.or_u 0
- # CHECK: i64.atomic.rmw8.or_u 0 # encoding: [0xfe,0x37,0x00,0x00]
+ # CHECK: i64.atomic.rmw8.or_u 0 seq_cst # encoding: [0xfe,0x37,0x00,0x00,0x04]
i64.atomic.rmw8.or_u 0
- # CHECK: i64.atomic.rmw16.or_u 48 # encoding: [0xfe,0x38,0x01,0x30]
+ # CHECK: i64.atomic.rmw16.or_u 48 seq_cst # encoding: [0xfe,0x38,0x01,0x30,0x04]
i64.atomic.rmw16.or_u 48
- # CHECK: i64.atomic.rmw32.or_u 0 # encoding: [0xfe,0x39,0x02,0x00]
+ # CHECK: i64.atomic.rmw32.or_u 0 seq_cst # encoding: [0xfe,0x39,0x02,0x00,0x04]
i64.atomic.rmw32.or_u 0
- # CHECK: i32.atomic.rmw.xor 0 # encoding: [0xfe,0x3a,0x02,0x00]
+ # CHECK: i32.atomic.rmw.xor 0 seq_cst # encoding: [0xfe,0x3a,0x02,0x00,0x04]
i32.atomic.rmw.xor 0
- # CHECK: i64.atomic.rmw.xor 0 # encoding: [0xfe,0x3b,0x03,0x00]
+ # CHECK: i64.atomic.rmw.xor 0 seq_cst # encoding: [0xfe,0x3b,0x03,0x00,0x04]
i64.atomic.rmw.xor 0
- # CHECK: i32.atomic.rmw8.xor_u 4 # encoding: [0xfe,0x3c,0x00,0x04]
+ # CHECK: i32.atomic.rmw8.xor_u 4 seq_cst # encoding: [0xfe,0x3c,0x00,0x04,0x04]
i32.atomic.rmw8.xor_u 4
- # CHECK: i32.atomic.rmw16.xor_u 0 # encoding: [0xfe,0x3d,0x01,0x00]
+ # CHECK: i32.atomic.rmw16.xor_u 0 seq_cst # encoding: [0xfe,0x3d,0x01,0x00,0x04]
i32.atomic.rmw16.xor_u 0
- # CHECK: i64.atomic.rmw8.xor_u 0 # encoding: [0xfe,0x3e,0x00,0x00]
+ # CHECK: i64.atomic.rmw8.xor_u 0 seq_cst # encoding: [0xfe,0x3e,0x00,0x00,0x04]
i64.atomic.rmw8.xor_u 0
- # CHECK: i64.atomic.rmw16.xor_u 0 # encoding: [0xfe,0x3f,0x01,0x00]
+ # CHECK: i64.atomic.rmw16.xor_u 0 seq_cst # encoding: [0xfe,0x3f,0x01,0x00,0x04]
i64.atomic.rmw16.xor_u 0
- # CHECK: i64.atomic.rmw32.xor_u 0 # encoding: [0xfe,0x40,0x02,0x00]
+ # CHECK: i64.atomic.rmw32.xor_u 0 seq_cst # encoding: [0xfe,0x40,0x02,0x00,0x04]
i64.atomic.rmw32.xor_u 0
- # CHECK: i32.atomic.rmw.xchg 0 # encoding: [0xfe,0x41,0x02,0x00]
+ # CHECK: i32.atomic.rmw.xchg 0 seq_cst # encoding: [0xfe,0x41,0x02,0x00,0x04]
i32.atomic.rmw.xchg 0
- # CHECK: i64.atomic.rmw.xchg 0 # encoding: [0xfe,0x42,0x03,0x00]
+ # CHECK: i64.atomic.rmw.xchg 0 seq_cst # encoding: [0xfe,0x42,0x03,0x00,0x04]
i64.atomic.rmw.xchg 0
- # CHECK: i32.atomic.rmw8.xchg_u 0 # encoding: [0xfe,0x43,0x00,0x00]
+ # CHECK: i32.atomic.rmw8.xchg_u 0 seq_cst # encoding: [0xfe,0x43,0x00,0x00,0x04]
i32.atomic.rmw8.xchg_u 0
- # CHECK: i32.atomic.rmw16.xchg_u 0 # encoding: [0xfe,0x44,0x01,0x00]
+ # CHECK: i32.atomic.rmw16.xchg_u 0 seq_cst # encoding: [0xfe,0x44,0x01,0x00,0x04]
i32.atomic.rmw16.xchg_u 0
- # CHECK: i64.atomic.rmw8.xchg_u 0 # encoding: [0xfe,0x45,0x00,0x00]
+ # CHECK: i64.atomic.rmw8.xchg_u 0 seq_cst # encoding: [0xfe,0x45,0x00,0x00,0x04]
i64.atomic.rmw8.xchg_u 0
- # CHECK: i64.atomic.rmw16.xchg_u 8 # encoding: [0xfe,0x46,0x01,0x08]
+ # CHECK: i64.atomic.rmw16.xchg_u 8 seq_cst # encoding: [0xfe,0x46,0x01,0x08,0x04]
i64.atomic.rmw16.xchg_u 8
- # CHECK: i64.atomic.rmw32.xchg_u 0 # encoding: [0xfe,0x47,0x02,0x00]
+ # CHECK: i64.atomic.rmw32.xchg_u 0 seq_cst # encoding: [0xfe,0x47,0x02,0x00,0x04]
i64.atomic.rmw32.xchg_u 0
- # CHECK: i32.atomic.rmw.cmpxchg 32 # encoding: [0xfe,0x48,0x02,0x20]
+ # CHECK: i32.atomic.rmw.cmpxchg 32 seq_cst # encoding: [0xfe,0x48,0x02,0x20,0x04]
i32.atomic.rmw.cmpxchg 32
- # CHECK: i64.atomic.rmw.cmpxchg 0 # encoding: [0xfe,0x49,0x03,0x00]
+ # CHECK: i64.atomic.rmw.cmpxchg 0 seq_cst # encoding: [0xfe,0x49,0x03,0x00,0x04]
i64.atomic.rmw.cmpxchg 0
- # CHECK: i32.atomic.rmw8.cmpxchg_u 0 # encoding: [0xfe,0x4a,0x00,0x00]
+ # CHECK: i32.atomic.rmw8.cmpxchg_u 0 seq_cst # encoding: [0xfe,0x4a,0x00,0x00,0x04]
i32.atomic.rmw8.cmpxchg_u 0
- # CHECK: i32.atomic.rmw16.cmpxchg_u 0 # encoding: [0xfe,0x4b,0x01,0x00]
+ # CHECK: i32.atomic.rmw16.cmpxchg_u 0 seq_cst # encoding: [0xfe,0x4b,0x01,0x00,0x04]
i32.atomic.rmw16.cmpxchg_u 0
- # CHECK: i64.atomic.rmw8.cmpxchg_u 16 # encoding: [0xfe,0x4c,0x00,0x10]
+ # CHECK: i64.atomic.rmw8.cmpxchg_u 16 seq_cst # encoding: [0xfe,0x4c,0x00,0x10,0x04]
i64.atomic.rmw8.cmpxchg_u 16
- # CHECK: i64.atomic.rmw16.cmpxchg_u 0 # encoding: [0xfe,0x4d,0x01,0x00]
+ # CHECK: i64.atomic.rmw16.cmpxchg_u 0 seq_cst # encoding: [0xfe,0x4d,0x01,0x00,0x04]
i64.atomic.rmw16.cmpxchg_u 0
- # CHECK: i64.atomic.rmw32.cmpxchg_u 0 # encoding: [0xfe,0x4e,0x02,0x00]
+ # CHECK: i64.atomic.rmw32.cmpxchg_u 0 seq_cst # encoding: [0xfe,0x4e,0x02,0x00,0x04]
i64.atomic.rmw32.cmpxchg_u 0
end_function
>From 474fde5f1f1f73dbfbd63c4c34225eb2d1ad4526 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 20 Feb 2026 06:23:08 +0000
Subject: [PATCH 02/22] gate behind a feature flag
---
.../AsmParser/WebAssemblyAsmParser.cpp | 2 +
.../Disassembler/WebAssemblyDisassembler.cpp | 5 +-
.../MCTargetDesc/WebAssemblyInstPrinter.cpp | 5 +
.../MCTargetDesc/WebAssemblyInstPrinter.h | 2 +
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 11 +-
llvm/lib/Target/WebAssembly/WebAssembly.td | 4 +
.../WebAssembly/WebAssemblyInstrInfo.td | 8 ++
.../Target/WebAssembly/WebAssemblySubtarget.h | 2 +
llvm/test/MC/WebAssembly/atomics-encodings.s | 128 +++++++++---------
.../MC/WebAssembly/atomics-orderings-errors.s | 15 ++
llvm/test/MC/WebAssembly/atomics-orderings.s | 61 +++++++++
11 files changed, 176 insertions(+), 67 deletions(-)
create mode 100644 llvm/test/MC/WebAssembly/atomics-orderings-errors.s
create mode 100644 llvm/test/MC/WebAssembly/atomics-orderings.s
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index ff60085a2f317..05f0af4e74a1c 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -485,6 +485,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
.Default(-1);
if (Order == -1)
return false;
+ if (!STI->checkFeatures("+shared-everything"))
+ return error("memory ordering requires shared-everything feature: ", Tok);
Operands.push_back(std::make_unique<WebAssemblyOperand>(
Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{Order}));
Parser.Lex();
diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index fa6086c7db076..fe6566af1bf9c 100644
--- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -255,8 +255,9 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
return MCDisassembler::Fail;
break;
}
- // Vector lane operands (not LEB encoded).
- case WebAssembly::OPERAND_VEC_I8IMM: {
+ // Vector lane operands and memory ordering (not LEB encoded).
+ case WebAssembly::OPERAND_VEC_I8IMM:
+ case WebAssembly::OPERAND_MEMORDER: {
if (!parseImmediate<uint8_t>(MI, Size, Bytes))
return MCDisassembler::Fail;
break;
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index a3730f9a3202c..bbf9082f09fc4 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -48,6 +48,7 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
StringRef Annot,
const MCSubtargetInfo &STI,
raw_ostream &OS) {
+ this->STI = &STI;
switch (MI->getOpcode()) {
case WebAssembly::CALL_INDIRECT_S:
case WebAssembly::RET_CALL_INDIRECT_S: {
@@ -374,6 +375,10 @@ void WebAssemblyInstPrinter::printWebAssemblyMemOrderOperand(const MCInst *MI,
unsigned OpNo,
raw_ostream &O) {
int64_t Imm = MI->getOperand(OpNo).getImm();
+ if (Imm == WebAssembly::MEM_ORDER_SEQ_CST &&
+ (!STI || !STI->getFeatureBits()[WebAssembly::FeatureSharedEverything]))
+ return;
+
switch (Imm) {
case WebAssembly::MEM_ORDER_NONE:
// none is the default, print nothing
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
index 7181641c81b3c..0caeb5a53b8e3 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
@@ -31,6 +31,8 @@ class WebAssemblyInstPrinter final : public MCInstPrinter {
enum EHInstKind { TRY, CATCH_LEGACY, CATCH_ALL_LEGACY };
SmallVector<EHInstKind, 4> EHInstStack;
+ const MCSubtargetInfo *STI = nullptr;
+
public:
WebAssemblyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
const MCRegisterInfo &MRI);
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 1de64ed142a1e..0565b65e52d96 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -111,10 +111,19 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
break;
case WebAssembly::OPERAND_SIGNATURE:
case WebAssembly::OPERAND_VEC_I8IMM:
- case WebAssembly::OPERAND_MEMORDER:
support::endian::write<uint8_t>(OS, MO.getImm(),
llvm::endianness::little);
break;
+ case WebAssembly::OPERAND_MEMORDER:
+ if (STI.getFeatureBits()[WebAssembly::FeatureSharedEverything]) {
+ support::endian::write<uint8_t>(OS, MO.getImm(),
+ llvm::endianness::little);
+ } else if (Opcode == WebAssembly::ATOMIC_FENCE ||
+ Opcode == WebAssembly::ATOMIC_FENCE_S) {
+ support::endian::write<uint8_t>(OS, 0,
+ llvm::endianness::little);
+ }
+ break;
case WebAssembly::OPERAND_VEC_I16IMM:
support::endian::write<uint16_t>(OS, MO.getImm(),
llvm::endianness::little);
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td
index 67a2331b26b6e..53cdc120a5931 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.td
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.td
@@ -81,6 +81,10 @@ def FeatureSignExt :
SubtargetFeature<"sign-ext", "HasSignExt", "true",
"Enable sign extension operators">;
+def FeatureSharedEverything :
+ SubtargetFeature<"shared-everything", "HasSharedEverything", "true",
+ "Enable shared-everything-threads proposal">;
+
def FeatureSIMD128 : SubtargetFeature<"simd128", "SIMDLevel", "SIMD128",
"Enable 128-bit SIMD">;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 083b85582aa75..d0f21491ae0a6 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -87,6 +87,14 @@ def HasSignExt :
Predicate<"Subtarget->hasSignExt()">,
AssemblerPredicate<(all_of FeatureSignExt), "sign-ext">;
+def HasSharedEverything :
+ Predicate<"Subtarget->hasSharedEverything()">,
+ AssemblerPredicate<(all_of FeatureSharedEverything), "shared-everything">;
+
+def NotHasSharedEverything :
+ Predicate<"!Subtarget->hasSharedEverything()">,
+ AssemblerPredicate<(all_of (not FeatureSharedEverything)), "shared-everything">;
+
def HasSIMD128 :
Predicate<"Subtarget->hasSIMD128()">,
AssemblerPredicate<(any_of FeatureSIMD128, FeatureRelaxedSIMD), "simd128">;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
index 256bd0d086d9e..03ec7685c679d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
@@ -57,6 +57,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
bool HasMutableGlobals = false;
bool HasNontrappingFPToInt = false;
bool HasReferenceTypes = false;
+ bool HasSharedEverything = false;
bool HasSignExt = false;
bool HasTailCall = false;
bool HasWideArithmetic = false;
@@ -119,6 +120,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
bool hasMutableGlobals() const { return HasMutableGlobals; }
bool hasNontrappingFPToInt() const { return HasNontrappingFPToInt; }
bool hasReferenceTypes() const { return HasReferenceTypes; }
+ bool hasSharedEverything() const { return HasSharedEverything; }
bool hasGC() const { return HasGC; }
bool hasRelaxedSIMD() const { return SIMDLevel >= RelaxedSIMD; }
bool hasSignExt() const { return HasSignExt; }
diff --git a/llvm/test/MC/WebAssembly/atomics-encodings.s b/llvm/test/MC/WebAssembly/atomics-encodings.s
index f7899b5f5e5d9..aa0117d623e45 100644
--- a/llvm/test/MC/WebAssembly/atomics-encodings.s
+++ b/llvm/test/MC/WebAssembly/atomics-encodings.s
@@ -10,142 +10,142 @@ main:
# CHECK: memory.atomic.wait64 0 # encoding: [0xfe,0x02,0x03,0x00]
memory.atomic.wait64 0
- # CHECK: atomic.fence seq_cst # encoding: [0xfe,0x03,0x04]
+ # CHECK: atomic.fence # encoding: [0xfe,0x03,0x00]
atomic.fence
- # CHECK: i32.atomic.load 0 seq_cst # encoding: [0xfe,0x10,0x02,0x00,0x04]
+ # CHECK: i32.atomic.load 0 # encoding: [0xfe,0x10,0x02,0x00]
i32.atomic.load 0
- # CHECK: i64.atomic.load 4 seq_cst # encoding: [0xfe,0x11,0x03,0x04,0x04]
+ # CHECK: i64.atomic.load 4 # encoding: [0xfe,0x11,0x03,0x04]
i64.atomic.load 4
- # CHECK: i32.atomic.load8_u 48 seq_cst # encoding: [0xfe,0x12,0x00,0x30,0x04]
+ # CHECK: i32.atomic.load8_u 48 # encoding: [0xfe,0x12,0x00,0x30]
i32.atomic.load8_u 48
- # CHECK: i32.atomic.load16_u 0 seq_cst # encoding: [0xfe,0x13,0x01,0x00,0x04]
+ # CHECK: i32.atomic.load16_u 0 # encoding: [0xfe,0x13,0x01,0x00]
i32.atomic.load16_u 0
- # CHECK: i64.atomic.load8_u 0 seq_cst # encoding: [0xfe,0x14,0x00,0x00,0x04]
+ # CHECK: i64.atomic.load8_u 0 # encoding: [0xfe,0x14,0x00,0x00]
i64.atomic.load8_u 0
- # CHECK: i64.atomic.load16_u 0 seq_cst # encoding: [0xfe,0x15,0x01,0x00,0x04]
+ # CHECK: i64.atomic.load16_u 0 # encoding: [0xfe,0x15,0x01,0x00]
i64.atomic.load16_u 0
- # CHECK: i64.atomic.load32_u 0 seq_cst # encoding: [0xfe,0x16,0x02,0x00,0x04]
+ # CHECK: i64.atomic.load32_u 0 # encoding: [0xfe,0x16,0x02,0x00]
i64.atomic.load32_u 0
- # CHECK: i32.atomic.store 0 seq_cst # encoding: [0xfe,0x17,0x02,0x00,0x04]
+ # CHECK: i32.atomic.store 0 # encoding: [0xfe,0x17,0x02,0x00]
i32.atomic.store 0
- # CHECK: i64.atomic.store 8 seq_cst # encoding: [0xfe,0x18,0x03,0x08,0x04]
+ # CHECK: i64.atomic.store 8 # encoding: [0xfe,0x18,0x03,0x08]
i64.atomic.store 8
- # CHECK: i32.atomic.store8 0 seq_cst # encoding: [0xfe,0x19,0x00,0x00,0x04]
+ # CHECK: i32.atomic.store8 0 # encoding: [0xfe,0x19,0x00,0x00]
i32.atomic.store8 0
- # CHECK: i32.atomic.store16 0 seq_cst # encoding: [0xfe,0x1a,0x01,0x00,0x04]
+ # CHECK: i32.atomic.store16 0 # encoding: [0xfe,0x1a,0x01,0x00]
i32.atomic.store16 0
- # CHECK: i64.atomic.store8 16 seq_cst # encoding: [0xfe,0x1b,0x00,0x10,0x04]
+ # CHECK: i64.atomic.store8 16 # encoding: [0xfe,0x1b,0x00,0x10]
i64.atomic.store8 16
- # CHECK: i64.atomic.store16 0 seq_cst # encoding: [0xfe,0x1c,0x01,0x00,0x04]
+ # CHECK: i64.atomic.store16 0 # encoding: [0xfe,0x1c,0x01,0x00]
i64.atomic.store16 0
- # CHECK: i64.atomic.store32 0 seq_cst # encoding: [0xfe,0x1d,0x02,0x00,0x04]
+ # CHECK: i64.atomic.store32 0 # encoding: [0xfe,0x1d,0x02,0x00]
i64.atomic.store32 0
- # CHECK: i32.atomic.rmw.add 0 seq_cst # encoding: [0xfe,0x1e,0x02,0x00,0x04]
+ # CHECK: i32.atomic.rmw.add 0 # encoding: [0xfe,0x1e,0x02,0x00]
i32.atomic.rmw.add 0
- # CHECK: i64.atomic.rmw.add 0 seq_cst # encoding: [0xfe,0x1f,0x03,0x00,0x04]
+ # CHECK: i64.atomic.rmw.add 0 # encoding: [0xfe,0x1f,0x03,0x00]
i64.atomic.rmw.add 0
- # CHECK: i32.atomic.rmw8.add_u 0 seq_cst # encoding: [0xfe,0x20,0x00,0x00,0x04]
+ # CHECK: i32.atomic.rmw8.add_u 0 # encoding: [0xfe,0x20,0x00,0x00]
i32.atomic.rmw8.add_u 0
- # CHECK: i32.atomic.rmw16.add_u 0 seq_cst # encoding: [0xfe,0x21,0x01,0x00,0x04]
+ # CHECK: i32.atomic.rmw16.add_u 0 # encoding: [0xfe,0x21,0x01,0x00]
i32.atomic.rmw16.add_u 0
- # CHECK: i64.atomic.rmw8.add_u 0 seq_cst # encoding: [0xfe,0x22,0x00,0x00,0x04]
+ # CHECK: i64.atomic.rmw8.add_u 0 # encoding: [0xfe,0x22,0x00,0x00]
i64.atomic.rmw8.add_u 0
- # CHECK: i64.atomic.rmw16.add_u 0 seq_cst # encoding: [0xfe,0x23,0x01,0x00,0x04]
+ # CHECK: i64.atomic.rmw16.add_u 0 # encoding: [0xfe,0x23,0x01,0x00]
i64.atomic.rmw16.add_u 0
- # CHECK: i64.atomic.rmw32.add_u 16 seq_cst # encoding: [0xfe,0x24,0x02,0x10,0x04]
+ # CHECK: i64.atomic.rmw32.add_u 16 # encoding: [0xfe,0x24,0x02,0x10]
i64.atomic.rmw32.add_u 16
- # CHECK: i32.atomic.rmw.sub 0 seq_cst # encoding: [0xfe,0x25,0x02,0x00,0x04]
+ # CHECK: i32.atomic.rmw.sub 0 # encoding: [0xfe,0x25,0x02,0x00]
i32.atomic.rmw.sub 0
- # CHECK: i64.atomic.rmw.sub 0 seq_cst # encoding: [0xfe,0x26,0x03,0x00,0x04]
+ # CHECK: i64.atomic.rmw.sub 0 # encoding: [0xfe,0x26,0x03,0x00]
i64.atomic.rmw.sub 0
- # CHECK: i32.atomic.rmw8.sub_u 0 seq_cst # encoding: [0xfe,0x27,0x00,0x00,0x04]
+ # CHECK: i32.atomic.rmw8.sub_u 0 # encoding: [0xfe,0x27,0x00,0x00]
i32.atomic.rmw8.sub_u 0
- # CHECK: i32.atomic.rmw16.sub_u 0 seq_cst # encoding: [0xfe,0x28,0x01,0x00,0x04]
+ # CHECK: i32.atomic.rmw16.sub_u 0 # encoding: [0xfe,0x28,0x01,0x00]
i32.atomic.rmw16.sub_u 0
- # CHECK: i64.atomic.rmw8.sub_u 8 seq_cst # encoding: [0xfe,0x29,0x00,0x08,0x04]
+ # CHECK: i64.atomic.rmw8.sub_u 8 # encoding: [0xfe,0x29,0x00,0x08]
i64.atomic.rmw8.sub_u 8
- # CHECK: i64.atomic.rmw16.sub_u 0 seq_cst # encoding: [0xfe,0x2a,0x01,0x00,0x04]
+ # CHECK: i64.atomic.rmw16.sub_u 0 # encoding: [0xfe,0x2a,0x01,0x00]
i64.atomic.rmw16.sub_u 0
- # CHECK: i64.atomic.rmw32.sub_u 0 seq_cst # encoding: [0xfe,0x2b,0x02,0x00,0x04]
+ # CHECK: i64.atomic.rmw32.sub_u 0 # encoding: [0xfe,0x2b,0x02,0x00]
i64.atomic.rmw32.sub_u 0
- # CHECK: i32.atomic.rmw.and 0 seq_cst # encoding: [0xfe,0x2c,0x02,0x00,0x04]
+ # CHECK: i32.atomic.rmw.and 0 # encoding: [0xfe,0x2c,0x02,0x00]
i32.atomic.rmw.and 0
- # CHECK: i64.atomic.rmw.and 0 seq_cst # encoding: [0xfe,0x2d,0x03,0x00,0x04]
+ # CHECK: i64.atomic.rmw.and 0 # encoding: [0xfe,0x2d,0x03,0x00]
i64.atomic.rmw.and 0
- # CHECK: i32.atomic.rmw8.and_u 0 seq_cst # encoding: [0xfe,0x2e,0x00,0x00,0x04]
+ # CHECK: i32.atomic.rmw8.and_u 0 # encoding: [0xfe,0x2e,0x00,0x00]
i32.atomic.rmw8.and_u 0
- # CHECK: i32.atomic.rmw16.and_u 0 seq_cst # encoding: [0xfe,0x2f,0x01,0x00,0x04]
+ # CHECK: i32.atomic.rmw16.and_u 0 # encoding: [0xfe,0x2f,0x01,0x00]
i32.atomic.rmw16.and_u 0
- # CHECK: i64.atomic.rmw8.and_u 96 seq_cst # encoding: [0xfe,0x30,0x00,0x60,0x04]
+ # CHECK: i64.atomic.rmw8.and_u 96 # encoding: [0xfe,0x30,0x00,0x60]
i64.atomic.rmw8.and_u 96
- # CHECK: i64.atomic.rmw16.and_u 0 seq_cst # encoding: [0xfe,0x31,0x01,0x00,0x04]
+ # CHECK: i64.atomic.rmw16.and_u 0 # encoding: [0xfe,0x31,0x01,0x00]
i64.atomic.rmw16.and_u 0
- # CHECK: i64.atomic.rmw32.and_u 0 seq_cst # encoding: [0xfe,0x32,0x02,0x00,0x04]
+ # CHECK: i64.atomic.rmw32.and_u 0 # encoding: [0xfe,0x32,0x02,0x00]
i64.atomic.rmw32.and_u 0
- # CHECK: i32.atomic.rmw.or 0 seq_cst # encoding: [0xfe,0x33,0x02,0x00,0x04]
+ # CHECK: i32.atomic.rmw.or 0 # encoding: [0xfe,0x33,0x02,0x00]
i32.atomic.rmw.or 0
- # CHECK: i64.atomic.rmw.or 0 seq_cst # encoding: [0xfe,0x34,0x03,0x00,0x04]
+ # CHECK: i64.atomic.rmw.or 0 # encoding: [0xfe,0x34,0x03,0x00]
i64.atomic.rmw.or 0
- # CHECK: i32.atomic.rmw8.or_u 0 seq_cst # encoding: [0xfe,0x35,0x00,0x00,0x04]
+ # CHECK: i32.atomic.rmw8.or_u 0 # encoding: [0xfe,0x35,0x00,0x00]
i32.atomic.rmw8.or_u 0
- # CHECK: i32.atomic.rmw16.or_u 0 seq_cst # encoding: [0xfe,0x36,0x01,0x00,0x04]
+ # CHECK: i32.atomic.rmw16.or_u 0 # encoding: [0xfe,0x36,0x01,0x00]
i32.atomic.rmw16.or_u 0
- # CHECK: i64.atomic.rmw8.or_u 0 seq_cst # encoding: [0xfe,0x37,0x00,0x00,0x04]
+ # CHECK: i64.atomic.rmw8.or_u 0 # encoding: [0xfe,0x37,0x00,0x00]
i64.atomic.rmw8.or_u 0
- # CHECK: i64.atomic.rmw16.or_u 48 seq_cst # encoding: [0xfe,0x38,0x01,0x30,0x04]
+ # CHECK: i64.atomic.rmw16.or_u 48 # encoding: [0xfe,0x38,0x01,0x30]
i64.atomic.rmw16.or_u 48
- # CHECK: i64.atomic.rmw32.or_u 0 seq_cst # encoding: [0xfe,0x39,0x02,0x00,0x04]
+ # CHECK: i64.atomic.rmw32.or_u 0 # encoding: [0xfe,0x39,0x02,0x00]
i64.atomic.rmw32.or_u 0
- # CHECK: i32.atomic.rmw.xor 0 seq_cst # encoding: [0xfe,0x3a,0x02,0x00,0x04]
+ # CHECK: i32.atomic.rmw.xor 0 # encoding: [0xfe,0x3a,0x02,0x00]
i32.atomic.rmw.xor 0
- # CHECK: i64.atomic.rmw.xor 0 seq_cst # encoding: [0xfe,0x3b,0x03,0x00,0x04]
+ # CHECK: i64.atomic.rmw.xor 0 # encoding: [0xfe,0x3b,0x03,0x00]
i64.atomic.rmw.xor 0
- # CHECK: i32.atomic.rmw8.xor_u 4 seq_cst # encoding: [0xfe,0x3c,0x00,0x04,0x04]
+ # CHECK: i32.atomic.rmw8.xor_u 4 # encoding: [0xfe,0x3c,0x00,0x04]
i32.atomic.rmw8.xor_u 4
- # CHECK: i32.atomic.rmw16.xor_u 0 seq_cst # encoding: [0xfe,0x3d,0x01,0x00,0x04]
+ # CHECK: i32.atomic.rmw16.xor_u 0 # encoding: [0xfe,0x3d,0x01,0x00]
i32.atomic.rmw16.xor_u 0
- # CHECK: i64.atomic.rmw8.xor_u 0 seq_cst # encoding: [0xfe,0x3e,0x00,0x00,0x04]
+ # CHECK: i64.atomic.rmw8.xor_u 0 # encoding: [0xfe,0x3e,0x00,0x00]
i64.atomic.rmw8.xor_u 0
- # CHECK: i64.atomic.rmw16.xor_u 0 seq_cst # encoding: [0xfe,0x3f,0x01,0x00,0x04]
+ # CHECK: i64.atomic.rmw16.xor_u 0 # encoding: [0xfe,0x3f,0x01,0x00]
i64.atomic.rmw16.xor_u 0
- # CHECK: i64.atomic.rmw32.xor_u 0 seq_cst # encoding: [0xfe,0x40,0x02,0x00,0x04]
+ # CHECK: i64.atomic.rmw32.xor_u 0 # encoding: [0xfe,0x40,0x02,0x00]
i64.atomic.rmw32.xor_u 0
- # CHECK: i32.atomic.rmw.xchg 0 seq_cst # encoding: [0xfe,0x41,0x02,0x00,0x04]
+ # CHECK: i32.atomic.rmw.xchg 0 # encoding: [0xfe,0x41,0x02,0x00]
i32.atomic.rmw.xchg 0
- # CHECK: i64.atomic.rmw.xchg 0 seq_cst # encoding: [0xfe,0x42,0x03,0x00,0x04]
+ # CHECK: i64.atomic.rmw.xchg 0 # encoding: [0xfe,0x42,0x03,0x00]
i64.atomic.rmw.xchg 0
- # CHECK: i32.atomic.rmw8.xchg_u 0 seq_cst # encoding: [0xfe,0x43,0x00,0x00,0x04]
+ # CHECK: i32.atomic.rmw8.xchg_u 0 # encoding: [0xfe,0x43,0x00,0x00]
i32.atomic.rmw8.xchg_u 0
- # CHECK: i32.atomic.rmw16.xchg_u 0 seq_cst # encoding: [0xfe,0x44,0x01,0x00,0x04]
+ # CHECK: i32.atomic.rmw16.xchg_u 0 # encoding: [0xfe,0x44,0x01,0x00]
i32.atomic.rmw16.xchg_u 0
- # CHECK: i64.atomic.rmw8.xchg_u 0 seq_cst # encoding: [0xfe,0x45,0x00,0x00,0x04]
+ # CHECK: i64.atomic.rmw8.xchg_u 0 # encoding: [0xfe,0x45,0x00,0x00]
i64.atomic.rmw8.xchg_u 0
- # CHECK: i64.atomic.rmw16.xchg_u 8 seq_cst # encoding: [0xfe,0x46,0x01,0x08,0x04]
+ # CHECK: i64.atomic.rmw16.xchg_u 8 # encoding: [0xfe,0x46,0x01,0x08]
i64.atomic.rmw16.xchg_u 8
- # CHECK: i64.atomic.rmw32.xchg_u 0 seq_cst # encoding: [0xfe,0x47,0x02,0x00,0x04]
+ # CHECK: i64.atomic.rmw32.xchg_u 0 # encoding: [0xfe,0x47,0x02,0x00]
i64.atomic.rmw32.xchg_u 0
- # CHECK: i32.atomic.rmw.cmpxchg 32 seq_cst # encoding: [0xfe,0x48,0x02,0x20,0x04]
+ # CHECK: i32.atomic.rmw.cmpxchg 32 # encoding: [0xfe,0x48,0x02,0x20]
i32.atomic.rmw.cmpxchg 32
- # CHECK: i64.atomic.rmw.cmpxchg 0 seq_cst # encoding: [0xfe,0x49,0x03,0x00,0x04]
+ # CHECK: i64.atomic.rmw.cmpxchg 0 # encoding: [0xfe,0x49,0x03,0x00]
i64.atomic.rmw.cmpxchg 0
- # CHECK: i32.atomic.rmw8.cmpxchg_u 0 seq_cst # encoding: [0xfe,0x4a,0x00,0x00,0x04]
+ # CHECK: i32.atomic.rmw8.cmpxchg_u 0 # encoding: [0xfe,0x4a,0x00,0x00]
i32.atomic.rmw8.cmpxchg_u 0
- # CHECK: i32.atomic.rmw16.cmpxchg_u 0 seq_cst # encoding: [0xfe,0x4b,0x01,0x00,0x04]
+ # CHECK: i32.atomic.rmw16.cmpxchg_u 0 # encoding: [0xfe,0x4b,0x01,0x00]
i32.atomic.rmw16.cmpxchg_u 0
- # CHECK: i64.atomic.rmw8.cmpxchg_u 16 seq_cst # encoding: [0xfe,0x4c,0x00,0x10,0x04]
+ # CHECK: i64.atomic.rmw8.cmpxchg_u 16 # encoding: [0xfe,0x4c,0x00,0x10]
i64.atomic.rmw8.cmpxchg_u 16
- # CHECK: i64.atomic.rmw16.cmpxchg_u 0 seq_cst # encoding: [0xfe,0x4d,0x01,0x00,0x04]
+ # CHECK: i64.atomic.rmw16.cmpxchg_u 0 # encoding: [0xfe,0x4d,0x01,0x00]
i64.atomic.rmw16.cmpxchg_u 0
- # CHECK: i64.atomic.rmw32.cmpxchg_u 0 seq_cst # encoding: [0xfe,0x4e,0x02,0x00,0x04]
+ # CHECK: i64.atomic.rmw32.cmpxchg_u 0 # encoding: [0xfe,0x4e,0x02,0x00]
i64.atomic.rmw32.cmpxchg_u 0
end_function
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings-errors.s b/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
new file mode 100644
index 0000000000000..6867d5ae308ad
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
@@ -0,0 +1,15 @@
+# RUN: not llvm-mc -triple=wasm32-unknown-unknown -mattr=+atomics < %s 2>&1 | FileCheck %s
+
+main:
+ .functype main () -> ()
+
+ # CHECK: :[[@LINE+1]]:16: error: memory ordering requires shared-everything feature: acquire
+ atomic.fence acquire
+
+ # CHECK: :[[@LINE+1]]:21: error: memory ordering requires shared-everything feature: release
+ i32.atomic.load 0 release
+
+ # CHECK: :[[@LINE+1]]:24: error: memory ordering requires shared-everything feature: seq_cst
+ i32.atomic.rmw.add 0 seq_cst
+
+ end_function
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings.s b/llvm/test/MC/WebAssembly/atomics-orderings.s
new file mode 100644
index 0000000000000..9ab8fd94238f4
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/atomics-orderings.s
@@ -0,0 +1,61 @@
+# RUN: llvm-mc -no-type-check -show-encoding -triple=wasm32-unknown-unknown -mattr=+atomics,+shared-everything < %s | FileCheck %s
+# RUN: llvm-mc -no-type-check -triple=wasm32-unknown-unknown -mattr=+atomics,+shared-everything %s -filetype=obj -o - | llvm-objdump -d --mattr=+atomics,+shared-everything - | FileCheck %s --check-prefix=DISASM
+
+main:
+ .functype main () -> ()
+
+ # CHECK: atomic.fence seq_cst # encoding: [0xfe,0x03,0x04]
+ # DISASM: atomic.fence seq_cst
+ atomic.fence
+ # CHECK: atomic.fence acquire # encoding: [0xfe,0x03,0x01]
+ # DISASM: atomic.fence acquire
+ atomic.fence acquire
+ # CHECK: atomic.fence release # encoding: [0xfe,0x03,0x02]
+ # DISASM: atomic.fence release
+ atomic.fence release
+ # CHECK: atomic.fence acq_rel # encoding: [0xfe,0x03,0x03]
+ # DISASM: atomic.fence acq_rel
+ atomic.fence acq_rel
+ # CHECK: atomic.fence seq_cst # encoding: [0xfe,0x03,0x04]
+ # DISASM: atomic.fence seq_cst
+ atomic.fence seq_cst
+
+ # CHECK: i32.atomic.load 0 seq_cst # encoding: [0xfe,0x10,0x02,0x00,0x04]
+ # DISASM: i32.atomic.load 0 seq_cst
+ i32.atomic.load 0
+ # CHECK: i32.atomic.load 0 acquire # encoding: [0xfe,0x10,0x02,0x00,0x01]
+ # DISASM: i32.atomic.load 0 acquire
+ i32.atomic.load 0 acquire
+ # CHECK: i32.atomic.load 0 seq_cst # encoding: [0xfe,0x10,0x02,0x00,0x04]
+ # DISASM: i32.atomic.load 0 seq_cst
+ i32.atomic.load 0 seq_cst
+
+ # CHECK: i64.atomic.load 0 release # encoding: [0xfe,0x11,0x03,0x00,0x02]
+ # DISASM: i64.atomic.load 0 release
+ i64.atomic.load 0 release
+
+ # CHECK: i32.atomic.store 0 release # encoding: [0xfe,0x17,0x02,0x00,0x02]
+ # DISASM: i32.atomic.store 0 release
+ i32.atomic.store 0 release
+
+ # CHECK: i64.atomic.store 8 release # encoding: [0xfe,0x18,0x03,0x08,0x02]
+ # DISASM: i64.atomic.store 8 release
+ i64.atomic.store 8 release
+
+ # CHECK: i32.atomic.rmw.add 0 acq_rel # encoding: [0xfe,0x1e,0x02,0x00,0x03]
+ # DISASM: i32.atomic.rmw.add 0 acq_rel
+ i32.atomic.rmw.add 0 acq_rel
+
+ # CHECK: i64.atomic.rmw.cmpxchg 0 acquire # encoding: [0xfe,0x49,0x03,0x00,0x01]
+ # DISASM: i64.atomic.rmw.cmpxchg 0 acquire
+ i64.atomic.rmw.cmpxchg 0 acquire
+
+ # CHECK: i32.atomic.load8_u 0 seq_cst # encoding: [0xfe,0x12,0x00,0x00,0x04]
+ # DISASM: i32.atomic.load8_u 0 seq_cst
+ i32.atomic.load8_u 0:p2align=0 seq_cst
+
+ # CHECK: i64.atomic.rmw32.xchg_u 0 release # encoding: [0xfe,0x47,0x02,0x00,0x02]
+ # DISASM: i64.atomic.rmw32.xchg_u 0 release
+ i64.atomic.rmw32.xchg_u 0 release
+
+ end_function
>From 1c7298478b1c5b4bd89bec3868d16e872f2a62d6 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Sat, 21 Feb 2026 00:49:19 +0000
Subject: [PATCH 03/22] support disassembly, just 2 orderings
---
.../AsmParser/WebAssemblyAsmParser.cpp | 2 -
.../Disassembler/WebAssemblyDisassembler.cpp | 33 ++++++++++-
.../MCTargetDesc/WebAssemblyInstPrinter.cpp | 9 ---
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 43 +++++++++++++-
.../MCTargetDesc/WebAssemblyMCTargetDesc.h | 7 +--
.../MC/WebAssembly/atomics-orderings-errors.s | 8 +--
llvm/test/MC/WebAssembly/atomics-orderings.s | 56 +++++++++----------
7 files changed, 102 insertions(+), 56 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 05f0af4e74a1c..f9f77425d6bf6 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -478,8 +478,6 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return false;
StringRef S = Tok.getString();
int64_t Order = StringSwitch<int64_t>(S)
- .Case("acquire", WebAssembly::MEM_ORDER_ACQUIRE)
- .Case("release", WebAssembly::MEM_ORDER_RELEASE)
.Case("acq_rel", WebAssembly::MEM_ORDER_ACQ_REL)
.Case("seq_cst", WebAssembly::MEM_ORDER_SEQ_CST)
.Default(-1);
diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index fe6566af1bf9c..d186fc8df3a38 100644
--- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -192,6 +192,7 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
// At this point we must have a valid instruction to decode.
assert(WasmInst->ET == ET_Instruction);
MI.setOpcode(WasmInst->Opcode);
+ bool HasBit5 = false;
// Parse any operands.
for (uint8_t OPI = 0; OPI < WasmInst->NumOperands; OPI++) {
auto OT = OperandTable[WasmInst->OperandStart + OPI];
@@ -210,6 +211,13 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
case MCOI::OPERAND_IMMEDIATE: {
if (!parseLEBImmediate(MI, Size, Bytes, false))
return MCDisassembler::Fail;
+ if (OT == WebAssembly::OPERAND_P2ALIGN) {
+ int64_t Val = MI.getOperand(MI.getNumOperands() - 1).getImm();
+ if (Val & 0x20) {
+ HasBit5 = true;
+ MI.getOperand(MI.getNumOperands() - 1).setImm(Val & ~0x20);
+ }
+ }
break;
}
// SLEB operands:
@@ -258,8 +266,29 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
// Vector lane operands and memory ordering (not LEB encoded).
case WebAssembly::OPERAND_VEC_I8IMM:
case WebAssembly::OPERAND_MEMORDER: {
- if (!parseImmediate<uint8_t>(MI, Size, Bytes))
- return MCDisassembler::Fail;
+ if (OT == WebAssembly::OPERAND_MEMORDER) {
+ bool HasP2Align = false;
+ for (uint8_t J = 0; J < OPI; J++)
+ if (OperandTable[WasmInst->OperandStart + J] ==
+ WebAssembly::OPERAND_P2ALIGN)
+ HasP2Align = true;
+ if (!HasP2Align || HasBit5) {
+ if (!parseImmediate<uint8_t>(MI, Size, Bytes))
+ return MCDisassembler::Fail;
+ uint8_t Val = MI.getOperand(MI.getNumOperands() - 1).getImm();
+ if (Val == 0x11 || Val == 0x01)
+ MI.getOperand(MI.getNumOperands() - 1)
+ .setImm(WebAssembly::MEM_ORDER_ACQ_REL);
+ else
+ MI.getOperand(MI.getNumOperands() - 1)
+ .setImm(WebAssembly::MEM_ORDER_SEQ_CST);
+ } else {
+ MI.addOperand(MCOperand::createImm(WebAssembly::MEM_ORDER_SEQ_CST));
+ }
+ } else {
+ if (!parseImmediate<uint8_t>(MI, Size, Bytes))
+ return MCDisassembler::Fail;
+ }
break;
}
case WebAssembly::OPERAND_VEC_I16IMM: {
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index bbf9082f09fc4..4914d6f27770a 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -380,15 +380,6 @@ void WebAssemblyInstPrinter::printWebAssemblyMemOrderOperand(const MCInst *MI,
return;
switch (Imm) {
- case WebAssembly::MEM_ORDER_NONE:
- // none is the default, print nothing
- return;
- case WebAssembly::MEM_ORDER_ACQUIRE:
- O << " acquire";
- break;
- case WebAssembly::MEM_ORDER_RELEASE:
- O << " release";
- break;
case WebAssembly::MEM_ORDER_ACQ_REL:
O << " acq_rel";
break;
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 0565b65e52d96..073ff1e8143fa 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -103,6 +103,22 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
case WebAssembly::OPERAND_I32IMM:
encodeSLEB128(int32_t(MO.getImm()), OS);
break;
+ case WebAssembly::OPERAND_P2ALIGN: {
+ uint64_t P2Align = MO.getImm();
+ if (STI.getFeatureBits()[WebAssembly::FeatureSharedEverything]) {
+ for (unsigned J = 0; J < MI.getNumOperands(); ++J) {
+ if (J < Desc.getNumOperands() &&
+ Desc.operands()[J].OperandType ==
+ WebAssembly::OPERAND_MEMORDER) {
+ if (MI.getOperand(J).getImm() != WebAssembly::MEM_ORDER_SEQ_CST)
+ P2Align |= 0x20;
+ break;
+ }
+ }
+ }
+ encodeULEB128(P2Align, OS);
+ break;
+ }
case WebAssembly::OPERAND_OFFSET32:
encodeULEB128(uint32_t(MO.getImm()), OS);
break;
@@ -114,16 +130,37 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
support::endian::write<uint8_t>(OS, MO.getImm(),
llvm::endianness::little);
break;
- case WebAssembly::OPERAND_MEMORDER:
+ case WebAssembly::OPERAND_MEMORDER: {
+ uint8_t Val = MO.getImm();
if (STI.getFeatureBits()[WebAssembly::FeatureSharedEverything]) {
- support::endian::write<uint8_t>(OS, MO.getImm(),
- llvm::endianness::little);
+ bool IsMemoryInst = false;
+ bool Bit5Set = false;
+ for (unsigned J = 0; J < MI.getNumOperands(); ++J) {
+ if (J < Desc.getNumOperands() &&
+ Desc.operands()[J].OperandType ==
+ WebAssembly::OPERAND_P2ALIGN) {
+ IsMemoryInst = true;
+ if (Val != WebAssembly::MEM_ORDER_SEQ_CST)
+ Bit5Set = true;
+ break;
+ }
+ }
+ if (!IsMemoryInst || Bit5Set) {
+ if (Val == WebAssembly::MEM_ORDER_ACQ_REL) {
+ StringRef Name = MCII.getName(Opcode);
+ if (Name.contains("RMW") || Name.contains("CMPXCHG"))
+ Val = 0x11;
+ }
+ support::endian::write<uint8_t>(OS, Val,
+ llvm::endianness::little);
+ }
} else if (Opcode == WebAssembly::ATOMIC_FENCE ||
Opcode == WebAssembly::ATOMIC_FENCE_S) {
support::endian::write<uint8_t>(OS, 0,
llvm::endianness::little);
}
break;
+ }
case WebAssembly::OPERAND_VEC_I16IMM:
support::endian::write<uint16_t>(OS, MO.getImm(),
llvm::endianness::little);
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
index 59b152251e053..b828dcb84416d 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
@@ -87,11 +87,8 @@ enum OperandType {
};
enum MemOrder {
- MEM_ORDER_NONE = 0,
- MEM_ORDER_ACQUIRE = 1,
- MEM_ORDER_RELEASE = 2,
- MEM_ORDER_ACQ_REL = 3,
- MEM_ORDER_SEQ_CST = 4,
+ MEM_ORDER_SEQ_CST = 0,
+ MEM_ORDER_ACQ_REL = 1,
};
} // end namespace WebAssembly
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings-errors.s b/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
index 6867d5ae308ad..78637f44998b2 100644
--- a/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
+++ b/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
@@ -3,11 +3,11 @@
main:
.functype main () -> ()
- # CHECK: :[[@LINE+1]]:16: error: memory ordering requires shared-everything feature: acquire
- atomic.fence acquire
+ # CHECK: :[[@LINE+1]]:16: error: memory ordering requires shared-everything feature: acq_rel
+ atomic.fence acq_rel
- # CHECK: :[[@LINE+1]]:21: error: memory ordering requires shared-everything feature: release
- i32.atomic.load 0 release
+ # CHECK: :[[@LINE+1]]:21: error: memory ordering requires shared-everything feature: acq_rel
+ i32.atomic.load 0 acq_rel
# CHECK: :[[@LINE+1]]:24: error: memory ordering requires shared-everything feature: seq_cst
i32.atomic.rmw.add 0 seq_cst
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings.s b/llvm/test/MC/WebAssembly/atomics-orderings.s
index 9ab8fd94238f4..d7f8cae4a6c8a 100644
--- a/llvm/test/MC/WebAssembly/atomics-orderings.s
+++ b/llvm/test/MC/WebAssembly/atomics-orderings.s
@@ -4,58 +4,52 @@
main:
.functype main () -> ()
- # CHECK: atomic.fence seq_cst # encoding: [0xfe,0x03,0x04]
+ # CHECK: atomic.fence seq_cst # encoding: [0xfe,0x03,0x00]
# DISASM: atomic.fence seq_cst
atomic.fence
- # CHECK: atomic.fence acquire # encoding: [0xfe,0x03,0x01]
- # DISASM: atomic.fence acquire
- atomic.fence acquire
- # CHECK: atomic.fence release # encoding: [0xfe,0x03,0x02]
- # DISASM: atomic.fence release
- atomic.fence release
- # CHECK: atomic.fence acq_rel # encoding: [0xfe,0x03,0x03]
+ # CHECK: atomic.fence acq_rel # encoding: [0xfe,0x03,0x01]
# DISASM: atomic.fence acq_rel
atomic.fence acq_rel
- # CHECK: atomic.fence seq_cst # encoding: [0xfe,0x03,0x04]
+ # CHECK: atomic.fence seq_cst # encoding: [0xfe,0x03,0x00]
# DISASM: atomic.fence seq_cst
atomic.fence seq_cst
- # CHECK: i32.atomic.load 0 seq_cst # encoding: [0xfe,0x10,0x02,0x00,0x04]
+ # CHECK: i32.atomic.load 0 seq_cst # encoding: [0xfe,0x10,0x02,0x00]
# DISASM: i32.atomic.load 0 seq_cst
i32.atomic.load 0
- # CHECK: i32.atomic.load 0 acquire # encoding: [0xfe,0x10,0x02,0x00,0x01]
- # DISASM: i32.atomic.load 0 acquire
- i32.atomic.load 0 acquire
- # CHECK: i32.atomic.load 0 seq_cst # encoding: [0xfe,0x10,0x02,0x00,0x04]
+ # CHECK: i32.atomic.load 0 acq_rel # encoding: [0xfe,0x10,0x22,0x00,0x01]
+ # DISASM: i32.atomic.load 0 acq_rel
+ i32.atomic.load 0 acq_rel
+ # CHECK: i32.atomic.load 0 seq_cst # encoding: [0xfe,0x10,0x02,0x00]
# DISASM: i32.atomic.load 0 seq_cst
i32.atomic.load 0 seq_cst
- # CHECK: i64.atomic.load 0 release # encoding: [0xfe,0x11,0x03,0x00,0x02]
- # DISASM: i64.atomic.load 0 release
- i64.atomic.load 0 release
+ # CHECK: i64.atomic.load 0 acq_rel # encoding: [0xfe,0x11,0x23,0x00,0x01]
+ # DISASM: i64.atomic.load 0 acq_rel
+ i64.atomic.load 0 acq_rel
- # CHECK: i32.atomic.store 0 release # encoding: [0xfe,0x17,0x02,0x00,0x02]
- # DISASM: i32.atomic.store 0 release
- i32.atomic.store 0 release
+ # CHECK: i32.atomic.store 0 acq_rel # encoding: [0xfe,0x17,0x22,0x00,0x01]
+ # DISASM: i32.atomic.store 0 acq_rel
+ i32.atomic.store 0 acq_rel
- # CHECK: i64.atomic.store 8 release # encoding: [0xfe,0x18,0x03,0x08,0x02]
- # DISASM: i64.atomic.store 8 release
- i64.atomic.store 8 release
+ # CHECK: i64.atomic.store 8 acq_rel # encoding: [0xfe,0x18,0x23,0x08,0x01]
+ # DISASM: i64.atomic.store 8 acq_rel
+ i64.atomic.store 8 acq_rel
- # CHECK: i32.atomic.rmw.add 0 acq_rel # encoding: [0xfe,0x1e,0x02,0x00,0x03]
+ # CHECK: i32.atomic.rmw.add 0 acq_rel # encoding: [0xfe,0x1e,0x22,0x00,0x11]
# DISASM: i32.atomic.rmw.add 0 acq_rel
i32.atomic.rmw.add 0 acq_rel
- # CHECK: i64.atomic.rmw.cmpxchg 0 acquire # encoding: [0xfe,0x49,0x03,0x00,0x01]
- # DISASM: i64.atomic.rmw.cmpxchg 0 acquire
- i64.atomic.rmw.cmpxchg 0 acquire
+ # CHECK: i64.atomic.rmw.cmpxchg 0 acq_rel # encoding: [0xfe,0x49,0x23,0x00,0x11]
+ # DISASM: i64.atomic.rmw.cmpxchg 0 acq_rel
+ i64.atomic.rmw.cmpxchg 0 acq_rel
- # CHECK: i32.atomic.load8_u 0 seq_cst # encoding: [0xfe,0x12,0x00,0x00,0x04]
+ # CHECK: i32.atomic.load8_u 0 seq_cst # encoding: [0xfe,0x12,0x00,0x00]
# DISASM: i32.atomic.load8_u 0 seq_cst
i32.atomic.load8_u 0:p2align=0 seq_cst
- # CHECK: i64.atomic.rmw32.xchg_u 0 release # encoding: [0xfe,0x47,0x02,0x00,0x02]
- # DISASM: i64.atomic.rmw32.xchg_u 0 release
- i64.atomic.rmw32.xchg_u 0 release
+ # CHECK: i64.atomic.rmw32.xchg_u 0 acq_rel # encoding: [0xfe,0x47,0x22,0x00,0x11]
+ # DISASM: i64.atomic.rmw32.xchg_u 0 acq_rel
+ i64.atomic.rmw32.xchg_u 0 acq_rel
end_function
>From b1ac71f1daa5803603f69573cb5a5f46dc7d99fb Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Sat, 21 Feb 2026 04:06:07 +0000
Subject: [PATCH 04/22] fix names for orderings
---
.../AsmParser/WebAssemblyAsmParser.cpp | 4 +-
.../MCTargetDesc/WebAssemblyInstPrinter.cpp | 4 +-
.../MC/WebAssembly/atomics-orderings-errors.s | 12 +--
llvm/test/MC/WebAssembly/atomics-orderings.s | 90 +++++++++----------
4 files changed, 55 insertions(+), 55 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index f9f77425d6bf6..8a4bb784dda09 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -478,8 +478,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return false;
StringRef S = Tok.getString();
int64_t Order = StringSwitch<int64_t>(S)
- .Case("acq_rel", WebAssembly::MEM_ORDER_ACQ_REL)
- .Case("seq_cst", WebAssembly::MEM_ORDER_SEQ_CST)
+ .Case("acqrel", WebAssembly::MEM_ORDER_ACQ_REL)
+ .Case("seqcst", WebAssembly::MEM_ORDER_SEQ_CST)
.Default(-1);
if (Order == -1)
return false;
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 4914d6f27770a..8bf22e6b789ee 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -381,10 +381,10 @@ void WebAssemblyInstPrinter::printWebAssemblyMemOrderOperand(const MCInst *MI,
switch (Imm) {
case WebAssembly::MEM_ORDER_ACQ_REL:
- O << " acq_rel";
+ O << " acqrel";
break;
case WebAssembly::MEM_ORDER_SEQ_CST:
- O << " seq_cst";
+ O << " seqcst";
break;
default:
llvm_unreachable("Unknown memory ordering");
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings-errors.s b/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
index 78637f44998b2..43b552e57d486 100644
--- a/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
+++ b/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
@@ -3,13 +3,13 @@
main:
.functype main () -> ()
- # CHECK: :[[@LINE+1]]:16: error: memory ordering requires shared-everything feature: acq_rel
- atomic.fence acq_rel
+ # CHECK: :[[@LINE+1]]:16: error: memory ordering requires shared-everything feature: acqrel
+ atomic.fence acqrel
- # CHECK: :[[@LINE+1]]:21: error: memory ordering requires shared-everything feature: acq_rel
- i32.atomic.load 0 acq_rel
+ # CHECK: :[[@LINE+1]]:21: error: memory ordering requires shared-everything feature: acqrel
+ i32.atomic.load 0 acqrel
- # CHECK: :[[@LINE+1]]:24: error: memory ordering requires shared-everything feature: seq_cst
- i32.atomic.rmw.add 0 seq_cst
+ # CHECK: :[[@LINE+1]]:24: error: memory ordering requires shared-everything feature: seqcst
+ i32.atomic.rmw.add 0 seqcst
end_function
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings.s b/llvm/test/MC/WebAssembly/atomics-orderings.s
index d7f8cae4a6c8a..de904231b54b5 100644
--- a/llvm/test/MC/WebAssembly/atomics-orderings.s
+++ b/llvm/test/MC/WebAssembly/atomics-orderings.s
@@ -4,52 +4,52 @@
main:
.functype main () -> ()
- # CHECK: atomic.fence seq_cst # encoding: [0xfe,0x03,0x00]
- # DISASM: atomic.fence seq_cst
+ # CHECK: atomic.fence seqcst # encoding: [0xfe,0x03,0x00]
+ # DISASM: atomic.fence seqcst
atomic.fence
- # CHECK: atomic.fence acq_rel # encoding: [0xfe,0x03,0x01]
- # DISASM: atomic.fence acq_rel
- atomic.fence acq_rel
- # CHECK: atomic.fence seq_cst # encoding: [0xfe,0x03,0x00]
- # DISASM: atomic.fence seq_cst
- atomic.fence seq_cst
-
- # CHECK: i32.atomic.load 0 seq_cst # encoding: [0xfe,0x10,0x02,0x00]
- # DISASM: i32.atomic.load 0 seq_cst
+ # CHECK: atomic.fence acqrel # encoding: [0xfe,0x03,0x01]
+ # DISASM: atomic.fence acqrel
+ atomic.fence acqrel
+ # CHECK: atomic.fence seqcst # encoding: [0xfe,0x03,0x00]
+ # DISASM: atomic.fence seqcst
+ atomic.fence seqcst
+
+ # CHECK: i32.atomic.load 0 seqcst # encoding: [0xfe,0x10,0x02,0x00]
+ # DISASM: i32.atomic.load 0 seqcst
i32.atomic.load 0
- # CHECK: i32.atomic.load 0 acq_rel # encoding: [0xfe,0x10,0x22,0x00,0x01]
- # DISASM: i32.atomic.load 0 acq_rel
- i32.atomic.load 0 acq_rel
- # CHECK: i32.atomic.load 0 seq_cst # encoding: [0xfe,0x10,0x02,0x00]
- # DISASM: i32.atomic.load 0 seq_cst
- i32.atomic.load 0 seq_cst
-
- # CHECK: i64.atomic.load 0 acq_rel # encoding: [0xfe,0x11,0x23,0x00,0x01]
- # DISASM: i64.atomic.load 0 acq_rel
- i64.atomic.load 0 acq_rel
-
- # CHECK: i32.atomic.store 0 acq_rel # encoding: [0xfe,0x17,0x22,0x00,0x01]
- # DISASM: i32.atomic.store 0 acq_rel
- i32.atomic.store 0 acq_rel
-
- # CHECK: i64.atomic.store 8 acq_rel # encoding: [0xfe,0x18,0x23,0x08,0x01]
- # DISASM: i64.atomic.store 8 acq_rel
- i64.atomic.store 8 acq_rel
-
- # CHECK: i32.atomic.rmw.add 0 acq_rel # encoding: [0xfe,0x1e,0x22,0x00,0x11]
- # DISASM: i32.atomic.rmw.add 0 acq_rel
- i32.atomic.rmw.add 0 acq_rel
-
- # CHECK: i64.atomic.rmw.cmpxchg 0 acq_rel # encoding: [0xfe,0x49,0x23,0x00,0x11]
- # DISASM: i64.atomic.rmw.cmpxchg 0 acq_rel
- i64.atomic.rmw.cmpxchg 0 acq_rel
-
- # CHECK: i32.atomic.load8_u 0 seq_cst # encoding: [0xfe,0x12,0x00,0x00]
- # DISASM: i32.atomic.load8_u 0 seq_cst
- i32.atomic.load8_u 0:p2align=0 seq_cst
-
- # CHECK: i64.atomic.rmw32.xchg_u 0 acq_rel # encoding: [0xfe,0x47,0x22,0x00,0x11]
- # DISASM: i64.atomic.rmw32.xchg_u 0 acq_rel
- i64.atomic.rmw32.xchg_u 0 acq_rel
+ # CHECK: i32.atomic.load 0 acqrel # encoding: [0xfe,0x10,0x22,0x00,0x01]
+ # DISASM: i32.atomic.load 0 acqrel
+ i32.atomic.load 0 acqrel
+ # CHECK: i32.atomic.load 0 seqcst # encoding: [0xfe,0x10,0x02,0x00]
+ # DISASM: i32.atomic.load 0 seqcst
+ i32.atomic.load 0 seqcst
+
+ # CHECK: i64.atomic.load 0 acqrel # encoding: [0xfe,0x11,0x23,0x00,0x01]
+ # DISASM: i64.atomic.load 0 acqrel
+ i64.atomic.load 0 acqrel
+
+ # CHECK: i32.atomic.store 0 acqrel # encoding: [0xfe,0x17,0x22,0x00,0x01]
+ # DISASM: i32.atomic.store 0 acqrel
+ i32.atomic.store 0 acqrel
+
+ # CHECK: i64.atomic.store 8 acqrel # encoding: [0xfe,0x18,0x23,0x08,0x01]
+ # DISASM: i64.atomic.store 8 acqrel
+ i64.atomic.store 8 acqrel
+
+ # CHECK: i32.atomic.rmw.add 0 acqrel # encoding: [0xfe,0x1e,0x22,0x00,0x11]
+ # DISASM: i32.atomic.rmw.add 0 acqrel
+ i32.atomic.rmw.add 0 acqrel
+
+ # CHECK: i64.atomic.rmw.cmpxchg 0 acqrel # encoding: [0xfe,0x49,0x23,0x00,0x11]
+ # DISASM: i64.atomic.rmw.cmpxchg 0 acqrel
+ i64.atomic.rmw.cmpxchg 0 acqrel
+
+ # CHECK: i32.atomic.load8_u 0 seqcst # encoding: [0xfe,0x12,0x00,0x00]
+ # DISASM: i32.atomic.load8_u 0 seqcst
+ i32.atomic.load8_u 0:p2align=0 seqcst
+
+ # CHECK: i64.atomic.rmw32.xchg_u 0 acqrel # encoding: [0xfe,0x47,0x22,0x00,0x11]
+ # DISASM: i64.atomic.rmw32.xchg_u 0 acqrel
+ i64.atomic.rmw32.xchg_u 0 acqrel
end_function
>From 9adffe13ca97de8fa7dac450a2d8ee4591ed5178 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Sat, 21 Feb 2026 05:30:53 +0000
Subject: [PATCH 05/22] fix ordering
---
.../Disassembler/WebAssemblyDisassembler.cpp | 42 ++++++++-------
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 54 +++++++++++--------
llvm/test/MC/WebAssembly/atomics-orderings.s | 14 ++---
3 files changed, 64 insertions(+), 46 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index d186fc8df3a38..3eb98ed6d76ce 100644
--- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -43,6 +43,7 @@ static constexpr int WebAssemblyInstructionTableSize = 256;
namespace {
class WebAssemblyDisassembler final : public MCDisassembler {
std::unique_ptr<const MCInstrInfo> MCII;
+ mutable std::optional<uint8_t> DecodedOrder;
DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
ArrayRef<uint8_t> Bytes, uint64_t Address,
@@ -164,6 +165,7 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
raw_ostream &CS) const {
CommentStream = &CS;
Size = 0;
+ DecodedOrder.reset();
int Opc = nextByte(Bytes, Size);
if (Opc < 0)
return MCDisassembler::Fail;
@@ -192,7 +194,6 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
// At this point we must have a valid instruction to decode.
assert(WasmInst->ET == ET_Instruction);
MI.setOpcode(WasmInst->Opcode);
- bool HasBit5 = false;
// Parse any operands.
for (uint8_t OPI = 0; OPI < WasmInst->NumOperands; OPI++) {
auto OT = OperandTable[WasmInst->OperandStart + OPI];
@@ -214,8 +215,10 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
if (OT == WebAssembly::OPERAND_P2ALIGN) {
int64_t Val = MI.getOperand(MI.getNumOperands() - 1).getImm();
if (Val & 0x20) {
- HasBit5 = true;
MI.getOperand(MI.getNumOperands() - 1).setImm(Val & ~0x20);
+ if (Size >= Bytes.size())
+ return MCDisassembler::Fail;
+ DecodedOrder = Bytes[Size++];
}
}
break;
@@ -267,24 +270,27 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
case WebAssembly::OPERAND_VEC_I8IMM:
case WebAssembly::OPERAND_MEMORDER: {
if (OT == WebAssembly::OPERAND_MEMORDER) {
- bool HasP2Align = false;
- for (uint8_t J = 0; J < OPI; J++)
- if (OperandTable[WasmInst->OperandStart + J] ==
- WebAssembly::OPERAND_P2ALIGN)
- HasP2Align = true;
- if (!HasP2Align || HasBit5) {
- if (!parseImmediate<uint8_t>(MI, Size, Bytes))
- return MCDisassembler::Fail;
- uint8_t Val = MI.getOperand(MI.getNumOperands() - 1).getImm();
- if (Val == 0x11 || Val == 0x01)
- MI.getOperand(MI.getNumOperands() - 1)
- .setImm(WebAssembly::MEM_ORDER_ACQ_REL);
- else
- MI.getOperand(MI.getNumOperands() - 1)
- .setImm(WebAssembly::MEM_ORDER_SEQ_CST);
+ uint8_t Val;
+ if (DecodedOrder) {
+ Val = *DecodedOrder;
} else {
- MI.addOperand(MCOperand::createImm(WebAssembly::MEM_ORDER_SEQ_CST));
+ bool HasP2Align = false;
+ for (uint8_t J = 0; J < OPI; J++)
+ if (OperandTable[WasmInst->OperandStart + J] ==
+ WebAssembly::OPERAND_P2ALIGN)
+ HasP2Align = true;
+ if (!HasP2Align) {
+ if (Size >= Bytes.size())
+ return MCDisassembler::Fail;
+ Val = Bytes[Size++];
+ } else {
+ Val = WebAssembly::MEM_ORDER_SEQ_CST;
+ }
}
+ if (Val == 0x11 || Val == 0x01)
+ MI.addOperand(MCOperand::createImm(WebAssembly::MEM_ORDER_ACQ_REL));
+ else
+ MI.addOperand(MCOperand::createImm(WebAssembly::MEM_ORDER_SEQ_CST));
} else {
if (!parseImmediate<uint8_t>(MI, Size, Bytes))
return MCDisassembler::Fail;
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 073ff1e8143fa..2d4812a5b99b8 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -110,13 +110,25 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
if (J < Desc.getNumOperands() &&
Desc.operands()[J].OperandType ==
WebAssembly::OPERAND_MEMORDER) {
- if (MI.getOperand(J).getImm() != WebAssembly::MEM_ORDER_SEQ_CST)
+ uint8_t Val = MI.getOperand(J).getImm();
+ if (Val != WebAssembly::MEM_ORDER_SEQ_CST) {
P2Align |= 0x20;
+ encodeULEB128(P2Align, OS);
+ if (Val == WebAssembly::MEM_ORDER_ACQ_REL) {
+ StringRef Name = MCII.getName(Opcode);
+ if (Name.contains("RMW") || Name.contains("CMPXCHG"))
+ Val = 0x11;
+ }
+ support::endian::write<uint8_t>(OS, Val,
+ llvm::endianness::little);
+ goto DoneP2Align;
+ }
break;
}
}
}
encodeULEB128(P2Align, OS);
+ DoneP2Align:
break;
}
case WebAssembly::OPERAND_OFFSET32:
@@ -131,29 +143,29 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
llvm::endianness::little);
break;
case WebAssembly::OPERAND_MEMORDER: {
+ bool IsMemoryInst = false;
+ for (unsigned J = 0; J < MI.getNumOperands(); ++J) {
+ if (J < Desc.getNumOperands() &&
+ Desc.operands()[J].OperandType ==
+ WebAssembly::OPERAND_P2ALIGN) {
+ IsMemoryInst = true;
+ break;
+ }
+ }
+ if (IsMemoryInst) {
+ // Already encoded in P2ALIGN case if non-default.
+ // If it was default (seqcst), nothing was encoded.
+ break;
+ }
uint8_t Val = MO.getImm();
if (STI.getFeatureBits()[WebAssembly::FeatureSharedEverything]) {
- bool IsMemoryInst = false;
- bool Bit5Set = false;
- for (unsigned J = 0; J < MI.getNumOperands(); ++J) {
- if (J < Desc.getNumOperands() &&
- Desc.operands()[J].OperandType ==
- WebAssembly::OPERAND_P2ALIGN) {
- IsMemoryInst = true;
- if (Val != WebAssembly::MEM_ORDER_SEQ_CST)
- Bit5Set = true;
- break;
- }
- }
- if (!IsMemoryInst || Bit5Set) {
- if (Val == WebAssembly::MEM_ORDER_ACQ_REL) {
- StringRef Name = MCII.getName(Opcode);
- if (Name.contains("RMW") || Name.contains("CMPXCHG"))
- Val = 0x11;
- }
- support::endian::write<uint8_t>(OS, Val,
- llvm::endianness::little);
+ if (Val == WebAssembly::MEM_ORDER_ACQ_REL) {
+ StringRef Name = MCII.getName(Opcode);
+ if (Name.contains("RMW") || Name.contains("CMPXCHG"))
+ Val = 0x11;
}
+ support::endian::write<uint8_t>(OS, Val,
+ llvm::endianness::little);
} else if (Opcode == WebAssembly::ATOMIC_FENCE ||
Opcode == WebAssembly::ATOMIC_FENCE_S) {
support::endian::write<uint8_t>(OS, 0,
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings.s b/llvm/test/MC/WebAssembly/atomics-orderings.s
index de904231b54b5..59ce4e7569723 100644
--- a/llvm/test/MC/WebAssembly/atomics-orderings.s
+++ b/llvm/test/MC/WebAssembly/atomics-orderings.s
@@ -17,30 +17,30 @@ main:
# CHECK: i32.atomic.load 0 seqcst # encoding: [0xfe,0x10,0x02,0x00]
# DISASM: i32.atomic.load 0 seqcst
i32.atomic.load 0
- # CHECK: i32.atomic.load 0 acqrel # encoding: [0xfe,0x10,0x22,0x00,0x01]
+ # CHECK: i32.atomic.load 0 acqrel # encoding: [0xfe,0x10,0x22,0x01,0x00]
# DISASM: i32.atomic.load 0 acqrel
i32.atomic.load 0 acqrel
# CHECK: i32.atomic.load 0 seqcst # encoding: [0xfe,0x10,0x02,0x00]
# DISASM: i32.atomic.load 0 seqcst
i32.atomic.load 0 seqcst
- # CHECK: i64.atomic.load 0 acqrel # encoding: [0xfe,0x11,0x23,0x00,0x01]
+ # CHECK: i64.atomic.load 0 acqrel # encoding: [0xfe,0x11,0x23,0x01,0x00]
# DISASM: i64.atomic.load 0 acqrel
i64.atomic.load 0 acqrel
- # CHECK: i32.atomic.store 0 acqrel # encoding: [0xfe,0x17,0x22,0x00,0x01]
+ # CHECK: i32.atomic.store 0 acqrel # encoding: [0xfe,0x17,0x22,0x01,0x00]
# DISASM: i32.atomic.store 0 acqrel
i32.atomic.store 0 acqrel
- # CHECK: i64.atomic.store 8 acqrel # encoding: [0xfe,0x18,0x23,0x08,0x01]
+ # CHECK: i64.atomic.store 8 acqrel # encoding: [0xfe,0x18,0x23,0x01,0x08]
# DISASM: i64.atomic.store 8 acqrel
i64.atomic.store 8 acqrel
- # CHECK: i32.atomic.rmw.add 0 acqrel # encoding: [0xfe,0x1e,0x22,0x00,0x11]
+ # CHECK: i32.atomic.rmw.add 0 acqrel # encoding: [0xfe,0x1e,0x22,0x11,0x00]
# DISASM: i32.atomic.rmw.add 0 acqrel
i32.atomic.rmw.add 0 acqrel
- # CHECK: i64.atomic.rmw.cmpxchg 0 acqrel # encoding: [0xfe,0x49,0x23,0x00,0x11]
+ # CHECK: i64.atomic.rmw.cmpxchg 0 acqrel # encoding: [0xfe,0x49,0x23,0x11,0x00]
# DISASM: i64.atomic.rmw.cmpxchg 0 acqrel
i64.atomic.rmw.cmpxchg 0 acqrel
@@ -48,7 +48,7 @@ main:
# DISASM: i32.atomic.load8_u 0 seqcst
i32.atomic.load8_u 0:p2align=0 seqcst
- # CHECK: i64.atomic.rmw32.xchg_u 0 acqrel # encoding: [0xfe,0x47,0x22,0x00,0x11]
+ # CHECK: i64.atomic.rmw32.xchg_u 0 acqrel # encoding: [0xfe,0x47,0x22,0x11,0x00]
# DISASM: i64.atomic.rmw32.xchg_u 0 acqrel
i64.atomic.rmw32.xchg_u 0 acqrel
>From a850fd78c59c4113277cbf963c22068a81d04c5d Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Tue, 24 Feb 2026 02:42:14 +0000
Subject: [PATCH 06/22] split cases
---
.../Disassembler/WebAssemblyDisassembler.cpp | 48 +++++++++----------
1 file changed, 23 insertions(+), 25 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index 3eb98ed6d76ce..41ce0db440314 100644
--- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -266,35 +266,33 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
return MCDisassembler::Fail;
break;
}
- // Vector lane operands and memory ordering (not LEB encoded).
- case WebAssembly::OPERAND_VEC_I8IMM:
+ case WebAssembly::OPERAND_VEC_I8IMM: {
+ if (!parseImmediate<uint8_t>(MI, Size, Bytes))
+ return MCDisassembler::Fail;
+ break;
+ }
case WebAssembly::OPERAND_MEMORDER: {
- if (OT == WebAssembly::OPERAND_MEMORDER) {
- uint8_t Val;
- if (DecodedOrder) {
- Val = *DecodedOrder;
+ uint8_t Val;
+ if (DecodedOrder) {
+ Val = *DecodedOrder;
+ } else {
+ bool HasP2Align = false;
+ for (uint8_t J = 0; J < OPI; J++)
+ if (OperandTable[WasmInst->OperandStart + J] ==
+ WebAssembly::OPERAND_P2ALIGN)
+ HasP2Align = true;
+ if (!HasP2Align) {
+ if (Size >= Bytes.size())
+ return MCDisassembler::Fail;
+ Val = Bytes[Size++];
} else {
- bool HasP2Align = false;
- for (uint8_t J = 0; J < OPI; J++)
- if (OperandTable[WasmInst->OperandStart + J] ==
- WebAssembly::OPERAND_P2ALIGN)
- HasP2Align = true;
- if (!HasP2Align) {
- if (Size >= Bytes.size())
- return MCDisassembler::Fail;
- Val = Bytes[Size++];
- } else {
- Val = WebAssembly::MEM_ORDER_SEQ_CST;
- }
+ Val = WebAssembly::MEM_ORDER_SEQ_CST;
}
- if (Val == 0x11 || Val == 0x01)
- MI.addOperand(MCOperand::createImm(WebAssembly::MEM_ORDER_ACQ_REL));
- else
- MI.addOperand(MCOperand::createImm(WebAssembly::MEM_ORDER_SEQ_CST));
- } else {
- if (!parseImmediate<uint8_t>(MI, Size, Bytes))
- return MCDisassembler::Fail;
}
+ if (Val == 0x11 || Val == 0x01)
+ MI.addOperand(MCOperand::createImm(WebAssembly::MEM_ORDER_ACQ_REL));
+ else
+ MI.addOperand(MCOperand::createImm(WebAssembly::MEM_ORDER_SEQ_CST));
break;
}
case WebAssembly::OPERAND_VEC_I16IMM: {
>From 1d3286eedd0d3fd164ac583e145f3217feb412a2 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Tue, 24 Feb 2026 21:55:01 +0000
Subject: [PATCH 07/22] move binary format defines, add one for RMW, cleanup
---
llvm/include/llvm/BinaryFormat/Wasm.h | 8 ++++++++
.../AsmParser/WebAssemblyAsmParser.cpp | 6 +++---
.../Disassembler/WebAssemblyDisassembler.cpp | 16 ++++++++--------
.../MCTargetDesc/WebAssemblyInstPrinter.cpp | 6 +++---
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 10 +++++-----
.../MCTargetDesc/WebAssemblyMCTargetDesc.h | 5 -----
6 files changed, 27 insertions(+), 24 deletions(-)
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index cf90a43d0d7e8..f56e1b2594b04 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -81,6 +81,14 @@ enum : unsigned {
WASM_TYPE_NORESULT = 0x40, // for blocks with no result values
};
+// Memory ordering encodings for atomic instructions.
+enum : unsigned {
+ WASM_MEM_ORDER_SEQ_CST = 0x00,
+ WASM_MEM_ORDER_ACQ_REL = 0x01,
+ // RMW/CMPXCHG operations have 2 orderings but they must currently match.
+ WASM_MEM_ORDER_RMW_ACQ_REL = 0x11,
+};
+
// Kinds of externals (for imports and exports).
enum : unsigned {
WASM_EXTERNAL_FUNCTION = 0x0,
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 8a4bb784dda09..f33297867941e 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -478,8 +478,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return false;
StringRef S = Tok.getString();
int64_t Order = StringSwitch<int64_t>(S)
- .Case("acqrel", WebAssembly::MEM_ORDER_ACQ_REL)
- .Case("seqcst", WebAssembly::MEM_ORDER_SEQ_CST)
+ .Case("acqrel", wasm::WASM_MEM_ORDER_ACQ_REL)
+ .Case("seqcst", wasm::WASM_MEM_ORDER_SEQ_CST)
.Default(-1);
if (Order == -1)
return false;
@@ -1483,7 +1483,7 @@ bool isAtomic(unsigned Opc) {
for (unsigned i = 0; i < Inst.getNumOperands(); ++i) {
auto &Op = Inst.getOperand(i);
if (Op.isImm() && Op.getImm() == -1)
- Op.setImm(WebAssembly::MEM_ORDER_SEQ_CST);
+ Op.setImm(wasm::WASM_MEM_ORDER_SEQ_CST);
}
}
if (!SkipTypeCheck)
diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index 41ce0db440314..d71ba5978a903 100644
--- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -43,7 +43,6 @@ static constexpr int WebAssemblyInstructionTableSize = 256;
namespace {
class WebAssemblyDisassembler final : public MCDisassembler {
std::unique_ptr<const MCInstrInfo> MCII;
- mutable std::optional<uint8_t> DecodedOrder;
DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
ArrayRef<uint8_t> Bytes, uint64_t Address,
@@ -165,7 +164,7 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
raw_ostream &CS) const {
CommentStream = &CS;
Size = 0;
- DecodedOrder.reset();
+ uint8_t DecodedOrder = 0xFF;
int Opc = nextByte(Bytes, Size);
if (Opc < 0)
return MCDisassembler::Fail;
@@ -266,6 +265,7 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
return MCDisassembler::Fail;
break;
}
+ // Vector lane operands and memory ordering (not LEB encoded).
case WebAssembly::OPERAND_VEC_I8IMM: {
if (!parseImmediate<uint8_t>(MI, Size, Bytes))
return MCDisassembler::Fail;
@@ -273,8 +273,8 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
}
case WebAssembly::OPERAND_MEMORDER: {
uint8_t Val;
- if (DecodedOrder) {
- Val = *DecodedOrder;
+ if (DecodedOrder != 0xFF) {
+ Val = DecodedOrder;
} else {
bool HasP2Align = false;
for (uint8_t J = 0; J < OPI; J++)
@@ -286,13 +286,13 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
return MCDisassembler::Fail;
Val = Bytes[Size++];
} else {
- Val = WebAssembly::MEM_ORDER_SEQ_CST;
+ Val = wasm::WASM_MEM_ORDER_SEQ_CST;
}
}
- if (Val == 0x11 || Val == 0x01)
- MI.addOperand(MCOperand::createImm(WebAssembly::MEM_ORDER_ACQ_REL));
+ if (Val == wasm::WASM_MEM_ORDER_RMW_ACQ_REL || Val == wasm::WASM_MEM_ORDER_ACQ_REL)
+ MI.addOperand(MCOperand::createImm(wasm::WASM_MEM_ORDER_ACQ_REL));
else
- MI.addOperand(MCOperand::createImm(WebAssembly::MEM_ORDER_SEQ_CST));
+ MI.addOperand(MCOperand::createImm(wasm::WASM_MEM_ORDER_SEQ_CST));
break;
}
case WebAssembly::OPERAND_VEC_I16IMM: {
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 8bf22e6b789ee..2e30ccb586919 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -375,15 +375,15 @@ void WebAssemblyInstPrinter::printWebAssemblyMemOrderOperand(const MCInst *MI,
unsigned OpNo,
raw_ostream &O) {
int64_t Imm = MI->getOperand(OpNo).getImm();
- if (Imm == WebAssembly::MEM_ORDER_SEQ_CST &&
+ if (Imm == wasm::WASM_MEM_ORDER_SEQ_CST &&
(!STI || !STI->getFeatureBits()[WebAssembly::FeatureSharedEverything]))
return;
switch (Imm) {
- case WebAssembly::MEM_ORDER_ACQ_REL:
+ case wasm::WASM_MEM_ORDER_ACQ_REL:
O << " acqrel";
break;
- case WebAssembly::MEM_ORDER_SEQ_CST:
+ case wasm::WASM_MEM_ORDER_SEQ_CST:
O << " seqcst";
break;
default:
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 2d4812a5b99b8..ea489d7ffa9f8 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -111,13 +111,13 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
Desc.operands()[J].OperandType ==
WebAssembly::OPERAND_MEMORDER) {
uint8_t Val = MI.getOperand(J).getImm();
- if (Val != WebAssembly::MEM_ORDER_SEQ_CST) {
+ if (Val != wasm::WASM_MEM_ORDER_SEQ_CST) {
P2Align |= 0x20;
encodeULEB128(P2Align, OS);
- if (Val == WebAssembly::MEM_ORDER_ACQ_REL) {
+ if (Val == wasm::WASM_MEM_ORDER_ACQ_REL) {
StringRef Name = MCII.getName(Opcode);
if (Name.contains("RMW") || Name.contains("CMPXCHG"))
- Val = 0x11;
+ Val = wasm::WASM_MEM_ORDER_RMW_ACQ_REL;
}
support::endian::write<uint8_t>(OS, Val,
llvm::endianness::little);
@@ -159,10 +159,10 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
}
uint8_t Val = MO.getImm();
if (STI.getFeatureBits()[WebAssembly::FeatureSharedEverything]) {
- if (Val == WebAssembly::MEM_ORDER_ACQ_REL) {
+ if (Val == wasm::WASM_MEM_ORDER_ACQ_REL) {
StringRef Name = MCII.getName(Opcode);
if (Name.contains("RMW") || Name.contains("CMPXCHG"))
- Val = 0x11;
+ Val = wasm::WASM_MEM_ORDER_RMW_ACQ_REL;
}
support::endian::write<uint8_t>(OS, Val,
llvm::endianness::little);
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
index b828dcb84416d..623e7afb4a225 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
@@ -85,11 +85,6 @@ enum OperandType {
/// memory ordering immediate for atomic instructions.
OPERAND_MEMORDER,
};
-
-enum MemOrder {
- MEM_ORDER_SEQ_CST = 0,
- MEM_ORDER_ACQ_REL = 1,
-};
} // end namespace WebAssembly
namespace WebAssemblyII {
>From ac2781814f0b921fdeafa5850e983bef6e12297a Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Wed, 25 Feb 2026 17:55:59 +0000
Subject: [PATCH 08/22] [WebAssembly] Improve atomic instruction encoding and
testing
This change refines the implementation of acquire-release atomics in the
WebAssembly backend:
- Moved memory ordering constants to Wasm.h to align with binary format
definitions.
- Refactored WebAssemblyMCCodeEmitter to use a unified encodeMemArg
helper, ensuring correct field ordering (flags, index, order, offset)
and proper handling of symbolic offsets.
- Updated AsmParser to correctly handle memory ordering for atomic
notify and wait instructions.
- Corrected SelectionDAG patterns in WebAssemblyInstrAtomics.td to
include the required default memory ordering immediate.
- Fixed regressions in existing tests (offset.ll, exception.ll) by
ensuring correct ULEB128 bit-widths and fixup creation.
- Updated atomic-fence.mir to satisfy machine code verification.
All WebAssembly backend and MC tests are now passing.
---
llvm/include/llvm/BinaryFormat/Wasm.h | 1 +
.../AsmParser/WebAssemblyAsmParser.cpp | 15 +-
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 136 ++++++++++++------
.../WebAssembly/WebAssemblyInstrAtomics.td | 72 +++++-----
.../test/CodeGen/WebAssembly/atomic-fence.mir | 4 +-
5 files changed, 147 insertions(+), 81 deletions(-)
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index f56e1b2594b04..fa71b9b8480f1 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -88,6 +88,7 @@ enum : unsigned {
// RMW/CMPXCHG operations have 2 orderings but they must currently match.
WASM_MEM_ORDER_RMW_ACQ_REL = 0x11,
};
+const unsigned WASM_MEMARG_HAS_MEM_ORDER = 0x20;
// Kinds of externals (for imports and exports).
enum : unsigned {
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index f33297867941e..3c893d3d15b3f 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -523,8 +523,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
Operands.push_back(std::make_unique<WebAssemblyOperand>(
Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
}
- if (IsAtomic && !InstName.contains("fence") &&
- !InstName.contains("notify") && !InstName.contains("wait")) {
+ if (IsAtomic && !InstName.contains("fence")) {
if (!parseMemOrderMaybe(Operands)) {
auto Tok = Lexer.getTok();
Operands.push_back(std::make_unique<WebAssemblyOperand>(
@@ -1189,6 +1188,18 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
bool isAtomic(unsigned Opc) {
switch (Opc) {
+ case WebAssembly::MEMORY_ATOMIC_NOTIFY_A32:
+ case WebAssembly::MEMORY_ATOMIC_NOTIFY_A32_S:
+ case WebAssembly::MEMORY_ATOMIC_NOTIFY_A64:
+ case WebAssembly::MEMORY_ATOMIC_NOTIFY_A64_S:
+ case WebAssembly::MEMORY_ATOMIC_WAIT32_A32:
+ case WebAssembly::MEMORY_ATOMIC_WAIT32_A32_S:
+ case WebAssembly::MEMORY_ATOMIC_WAIT32_A64:
+ case WebAssembly::MEMORY_ATOMIC_WAIT32_A64_S:
+ case WebAssembly::MEMORY_ATOMIC_WAIT64_A32:
+ case WebAssembly::MEMORY_ATOMIC_WAIT64_A32_S:
+ case WebAssembly::MEMORY_ATOMIC_WAIT64_A64:
+ case WebAssembly::MEMORY_ATOMIC_WAIT64_A64_S:
case WebAssembly::ATOMIC_FENCE:
case WebAssembly::ATOMIC_FENCE_S:
case WebAssembly::ATOMIC_LOAD16_U_I32_A32:
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index ea489d7ffa9f8..ebed623155b53 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -13,6 +13,7 @@
#include "MCTargetDesc/WebAssemblyFixupKinds.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
@@ -47,6 +48,13 @@ class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const override;
+ void encodeMemArg(const MCInst &MI, unsigned I, const MCInstrDesc &Desc,
+ const MCSubtargetInfo &STI, raw_ostream &OS,
+ SmallSet<unsigned, 4> &HandledOperands,
+ SmallVectorImpl<MCFixup> &Fixups, uint64_t Start) const;
+
+ uint8_t getEncodedMemOrder(uint8_t Order, unsigned Opcode) const;
+
public:
WebAssemblyMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)
: MCII(MCII), Ctx{Ctx} {}
@@ -58,6 +66,88 @@ MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII,
return new WebAssemblyMCCodeEmitter(MCII, Ctx);
}
+uint8_t WebAssemblyMCCodeEmitter::getEncodedMemOrder(uint8_t Order,
+ unsigned Opcode) const {
+ if (Order == wasm::WASM_MEM_ORDER_ACQ_REL) {
+ StringRef Name = MCII.getName(Opcode);
+ if (Name.contains("RMW") || Name.contains("CMPXCHG"))
+ return wasm::WASM_MEM_ORDER_RMW_ACQ_REL;
+ }
+ return Order;
+}
+
+void WebAssemblyMCCodeEmitter::encodeMemArg(
+ const MCInst &MI, unsigned I, const MCInstrDesc &Desc,
+ const MCSubtargetInfo &STI, raw_ostream &OS,
+ SmallSet<unsigned, 4> &HandledOperands,
+ SmallVectorImpl<MCFixup> &Fixups, uint64_t Start) const {
+ unsigned P2AlignIdx = I;
+ std::optional<unsigned> OffsetIdx;
+ std::optional<unsigned> MemOrderIdx;
+
+ for (unsigned J = 0; J < MI.getNumOperands(); ++J) {
+ if (J < Desc.getNumOperands()) {
+ auto OT = Desc.operands()[J].OperandType;
+ if (OT == WebAssembly::OPERAND_OFFSET32 ||
+ OT == WebAssembly::OPERAND_OFFSET64)
+ OffsetIdx = J;
+ else if (OT == WebAssembly::OPERAND_MEMORDER)
+ MemOrderIdx = J;
+ }
+ }
+
+ uint64_t P2Align = MI.getOperand(P2AlignIdx).getImm();
+ uint8_t Order = wasm::WASM_MEM_ORDER_SEQ_CST;
+
+ // Memory instructions always have an ordering, but if it's SEQ_CST then we
+ // don't use the shared-everything encoding (even if shared everything is
+ // enabled) because the original encoding is smaller.
+ if (MemOrderIdx) {
+ Order = MI.getOperand(*MemOrderIdx).getImm();
+ if (Order != wasm::WASM_MEM_ORDER_SEQ_CST) {
+ assert(STI.getFeatureBits()[WebAssembly::FeatureSharedEverything] &&
+ "Non-default atomic ordering but feature not enabled");
+ P2Align |= wasm::WASM_MEMARG_HAS_MEM_ORDER;
+ }
+ }
+
+ encodeULEB128(P2Align, OS);
+
+ // Memory index will go here once we support multi-memory.
+
+ if (P2Align & wasm::WASM_MEMARG_HAS_MEM_ORDER) {
+ support::endian::write<uint8_t>(
+ OS, getEncodedMemOrder(Order, MI.getOpcode()),
+ llvm::endianness::little);
+ }
+
+ // We handled the MemOrder operand, even if we didn't encode it explicitly
+ if (MemOrderIdx)
+ HandledOperands.insert(*MemOrderIdx);
+
+ if (OffsetIdx) {
+ const MCOperand &MO = MI.getOperand(*OffsetIdx);
+ if (MO.isImm()) {
+ if (Desc.operands()[*OffsetIdx].OperandType == WebAssembly::OPERAND_OFFSET32)
+ encodeULEB128(uint32_t(MO.getImm()), OS);
+ else
+ encodeULEB128(uint64_t(MO.getImm()), OS);
+ } else {
+ assert(MO.isExpr());
+ llvm::MCFixupKind FixupKind =
+ Desc.operands()[*OffsetIdx].OperandType == WebAssembly::OPERAND_OFFSET32
+ ? WebAssembly::fixup_uleb128_i32
+ : WebAssembly::fixup_uleb128_i64;
+ raw_svector_ostream &SOS = static_cast<raw_svector_ostream &>(OS);
+ Fixups.push_back(
+ MCFixup::create(SOS.tell() - Start, MO.getExpr(), FixupKind));
+ ++MCNumFixups;
+ encodeULEB128(0, OS, FixupKind == WebAssembly::fixup_uleb128_i32 ? 5 : 10);
+ }
+ HandledOperands.insert(*OffsetIdx);
+ }
+}
+
void WebAssemblyMCCodeEmitter::encodeInstruction(
const MCInst &MI, SmallVectorImpl<char> &CB,
SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
@@ -89,7 +179,10 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
encodeULEB128(MI.getNumOperands() - 2, OS);
const MCInstrDesc &Desc = MCII.get(Opcode);
+ SmallSet<unsigned, 4> HandledOperands;
for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
+ if (HandledOperands.count(I))
+ continue;
const MCOperand &MO = MI.getOperand(I);
if (MO.isReg()) {
/* nothing to encode */
@@ -103,34 +196,9 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
case WebAssembly::OPERAND_I32IMM:
encodeSLEB128(int32_t(MO.getImm()), OS);
break;
- case WebAssembly::OPERAND_P2ALIGN: {
- uint64_t P2Align = MO.getImm();
- if (STI.getFeatureBits()[WebAssembly::FeatureSharedEverything]) {
- for (unsigned J = 0; J < MI.getNumOperands(); ++J) {
- if (J < Desc.getNumOperands() &&
- Desc.operands()[J].OperandType ==
- WebAssembly::OPERAND_MEMORDER) {
- uint8_t Val = MI.getOperand(J).getImm();
- if (Val != wasm::WASM_MEM_ORDER_SEQ_CST) {
- P2Align |= 0x20;
- encodeULEB128(P2Align, OS);
- if (Val == wasm::WASM_MEM_ORDER_ACQ_REL) {
- StringRef Name = MCII.getName(Opcode);
- if (Name.contains("RMW") || Name.contains("CMPXCHG"))
- Val = wasm::WASM_MEM_ORDER_RMW_ACQ_REL;
- }
- support::endian::write<uint8_t>(OS, Val,
- llvm::endianness::little);
- goto DoneP2Align;
- }
- break;
- }
- }
- }
- encodeULEB128(P2Align, OS);
- DoneP2Align:
+ case WebAssembly::OPERAND_P2ALIGN:
+ encodeMemArg(MI, I, Desc, STI, OS, HandledOperands, Fixups, Start);
break;
- }
case WebAssembly::OPERAND_OFFSET32:
encodeULEB128(uint32_t(MO.getImm()), OS);
break;
@@ -143,20 +211,6 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
llvm::endianness::little);
break;
case WebAssembly::OPERAND_MEMORDER: {
- bool IsMemoryInst = false;
- for (unsigned J = 0; J < MI.getNumOperands(); ++J) {
- if (J < Desc.getNumOperands() &&
- Desc.operands()[J].OperandType ==
- WebAssembly::OPERAND_P2ALIGN) {
- IsMemoryInst = true;
- break;
- }
- }
- if (IsMemoryInst) {
- // Already encoded in P2ALIGN case if non-default.
- // If it was default (seqcst), nothing was encoded.
- break;
- }
uint8_t Val = MO.getImm();
if (STI.getFeatureBits()[WebAssembly::FeatureSharedEverything]) {
if (Val == wasm::WASM_MEM_ORDER_ACQ_REL) {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
index b8228e27c841d..70f37dd1386fa 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
@@ -35,66 +35,66 @@ multiclass ATOMIC_NRI<dag oops, dag iops, list<dag> pattern, string asmstr = "",
let hasSideEffects = 1 in {
defm MEMORY_ATOMIC_NOTIFY_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$count),
- (outs), (ins P2Align:$p2align, offset32_op:$off), [],
- "memory.atomic.notify \t$dst, ${off}(${addr})${p2align}, $count",
- "memory.atomic.notify \t${off}${p2align}", 0x00, false>;
+ (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, I32:$count),
+ (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ "memory.atomic.notify \t$dst, ${off}(${addr})${p2align}${order}, $count",
+ "memory.atomic.notify \t${off}${p2align}${order}", 0x00, false>;
defm MEMORY_ATOMIC_NOTIFY_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$count),
- (outs), (ins P2Align:$p2align, offset64_op:$off), [],
- "memory.atomic.notify \t$dst, ${off}(${addr})${p2align}, $count",
- "memory.atomic.notify \t${off}${p2align}", 0x00, true>;
+ (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, I32:$count),
+ (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ "memory.atomic.notify \t$dst, ${off}(${addr})${p2align}${order}, $count",
+ "memory.atomic.notify \t${off}${p2align}${order}", 0x00, true>;
let mayLoad = 1 in {
defm MEMORY_ATOMIC_WAIT32_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$exp,
+ (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, I32:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, offset32_op:$off), [],
- "memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
- "memory.atomic.wait32 \t${off}${p2align}", 0x01, false>;
+ (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ "memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
+ "memory.atomic.wait32 \t${off}${p2align}${order}", 0x01, false>;
defm MEMORY_ATOMIC_WAIT32_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$exp,
+ (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, I32:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, offset64_op:$off), [],
- "memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
- "memory.atomic.wait32 \t${off}${p2align}", 0x01, true>;
+ (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ "memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
+ "memory.atomic.wait32 \t${off}${p2align}${order}", 0x01, true>;
defm MEMORY_ATOMIC_WAIT64_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I64:$exp,
+ (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, I64:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, offset32_op:$off), [],
- "memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
- "memory.atomic.wait64 \t${off}${p2align}", 0x02, false>;
+ (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ "memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
+ "memory.atomic.wait64 \t${off}${p2align}${order}", 0x02, false>;
defm MEMORY_ATOMIC_WAIT64_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I64:$exp,
+ (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, I64:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, offset64_op:$off), [],
- "memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
- "memory.atomic.wait64 \t${off}${p2align}", 0x02, true>;
+ (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ "memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
+ "memory.atomic.wait64 \t${off}${p2align}${order}", 0x02, true>;
} // mayLoad = 1
} // hasSideEffects = 1
def NotifyPat_A32 :
Pat<(i32 (int_wasm_memory_atomic_notify (AddrOps32 offset32_op:$offset, I32:$addr), I32:$count)),
- (MEMORY_ATOMIC_NOTIFY_A32 0, $offset, $addr, $count)>,
+ (MEMORY_ATOMIC_NOTIFY_A32 0, $offset, 0, $addr, $count)>,
Requires<[HasAddr32, HasAtomics]>;
def NotifyPat_A64 :
Pat<(i32 (int_wasm_memory_atomic_notify (AddrOps64 offset64_op:$offset, I64:$addr), I32:$count)),
- (MEMORY_ATOMIC_NOTIFY_A64 0, $offset, $addr, $count)>,
+ (MEMORY_ATOMIC_NOTIFY_A64 0, $offset, 0, $addr, $count)>,
Requires<[HasAddr64, HasAtomics]>;
multiclass WaitPat<ValueType ty, Intrinsic kind, string inst> {
def WaitPat_A32 :
Pat<(i32 (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$exp, I64:$timeout)),
- (!cast<NI>(inst#_A32) 0, $offset, $addr, $exp, $timeout)>,
+ (!cast<NI>(inst#_A32) 0, $offset, 0, $addr, $exp, $timeout)>,
Requires<[HasAddr32, HasAtomics]>;
def WaitPat_A64 :
Pat<(i32 (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$exp, I64:$timeout)),
- (!cast<NI>(inst#_A64) 0, $offset, $addr, $exp, $timeout)>,
+ (!cast<NI>(inst#_A64) 0, $offset, 0, $addr, $exp, $timeout)>,
Requires<[HasAddr64, HasAtomics]>;
}
@@ -141,10 +141,10 @@ multiclass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> {
multiclass AtomicLoadPat<ValueType ty, SDPatternOperator kind, string Name> {
def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr))),
- (!cast<NI>(Name # "_A32") 0, offset32_op:$offset, 4, I32:$addr)>,
+ (!cast<NI>(Name # "_A32") 0, offset32_op:$offset, 0, I32:$addr)>,
Requires<[HasAddr32, HasAtomics]>;
def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr))),
- (!cast<NI>(Name # "_A64") 0, offset64_op:$offset, 4, I64:$addr)>,
+ (!cast<NI>(Name # "_A64") 0, offset64_op:$offset, 0, I64:$addr)>,
Requires<[HasAddr64, HasAtomics]>;
}
@@ -241,10 +241,10 @@ defm ATOMIC_STORE_I64 : AtomicStore<I64, "i64.atomic.store", 0x18>;
multiclass AStorePat<ValueType ty, PatFrag kind, string inst> {
def : Pat<(kind ty:$val, (AddrOps32 offset32_op:$offset, I32:$addr)),
- (!cast<NI>(inst#_A32) 0, $offset, 4, $addr, $val)>,
+ (!cast<NI>(inst#_A32) 0, $offset, 0, $addr, $val)>,
Requires<[HasAddr32, HasAtomics]>;
def : Pat<(kind ty:$val, (AddrOps64 offset64_op:$offset, I64:$addr)),
- (!cast<NI>(inst#_A64) 0, $offset, 4, $addr, $val)>,
+ (!cast<NI>(inst#_A64) 0, $offset, 0, $addr, $val)>,
Requires<[HasAddr64, HasAtomics]>;
}
defm : AStorePat<i32, atomic_store_32, "ATOMIC_STORE_I32">;
@@ -378,10 +378,10 @@ defm ATOMIC_RMW32_U_XCHG_I64 :
multiclass BinRMWPat<ValueType ty, PatFrag kind, string inst> {
def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$val)),
- (!cast<NI>(inst#_A32) 0, $offset, 4, $addr, $val)>,
+ (!cast<NI>(inst#_A32) 0, $offset, 0, $addr, $val)>,
Requires<[HasAddr32, HasAtomics]>;
def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$val)),
- (!cast<NI>(inst#_A64) 0, $offset, 4, $addr, $val)>,
+ (!cast<NI>(inst#_A64) 0, $offset, 0, $addr, $val)>,
Requires<[HasAddr64, HasAtomics]>;
}
@@ -519,10 +519,10 @@ defm ATOMIC_RMW32_U_CMPXCHG_I64 :
multiclass TerRMWPat<ValueType ty, PatFrag kind, string inst> {
def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$exp, ty:$new)),
- (!cast<NI>(inst#_A32) 0, $offset, 4, $addr, $exp, $new)>,
+ (!cast<NI>(inst#_A32) 0, $offset, 0, $addr, $exp, $new)>,
Requires<[HasAddr32, HasAtomics]>;
def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$exp, ty:$new)),
- (!cast<NI>(inst#_A64) 0, $offset, 4, $addr, $exp, $new)>,
+ (!cast<NI>(inst#_A64) 0, $offset, 0, $addr, $exp, $new)>,
Requires<[HasAddr64, HasAtomics]>;
}
diff --git a/llvm/test/CodeGen/WebAssembly/atomic-fence.mir b/llvm/test/CodeGen/WebAssembly/atomic-fence.mir
index 5bfe85cd59244..4e8a32f09da77 100644
--- a/llvm/test/CodeGen/WebAssembly/atomic-fence.mir
+++ b/llvm/test/CodeGen/WebAssembly/atomic-fence.mir
@@ -34,7 +34,7 @@ body: |
liveins: $arguments
%0:i32 = CONST_I32 0, implicit-def $arguments
- %1:i32 = MEMORY_ATOMIC_NOTIFY_A32 2, 0, %0:i32, %0:i32, implicit-def $arguments
+ %1:i32 = MEMORY_ATOMIC_NOTIFY_A32 2, 0, 0, %0:i32, %0:i32, implicit-def $arguments
COMPILER_FENCE implicit-def $arguments
%2:i32 = ADD_I32 %0:i32, %0:i32, implicit-def $arguments
CALL @foo, %2:i32, %1:i32, implicit-def $arguments
@@ -58,7 +58,7 @@ body: |
liveins: $arguments
%0:i32 = CONST_I32 0, implicit-def $arguments
- %1:i32 = MEMORY_ATOMIC_NOTIFY_A32 2, 0, %0:i32, %0:i32, implicit-def $arguments
+ %1:i32 = MEMORY_ATOMIC_NOTIFY_A32 2, 0, 0, %0:i32, %0:i32, implicit-def $arguments
ATOMIC_FENCE 0, implicit-def $arguments
%2:i32 = ADD_I32 %0:i32, %0:i32, implicit-def $arguments
CALL @foo, %2:i32, %1:i32, implicit-def $arguments
>From 445d01c358e34e857b0c2dda9f1e1c5179641d90 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Wed, 25 Feb 2026 21:58:17 +0000
Subject: [PATCH 09/22] [WebAssembly] Reorder atomic instruction operands to
simplify encoding
This change reorders the MCInst operands for WebAssembly atomic instructions
from (p2align, offset, order) to (p2align, order, offset). This new order
matches the WebAssembly binary format's memarg structure for the
Shared-Everything Threads proposal, where the ordering byte precedes the
offset.
By aligning the MachineInstr operand order with the binary encoding, we
can significantly simplify WebAssemblyMCCodeEmitter::encodeMemArg. It
now only handles the p2align and order fields, allowing the generic
instruction encoding path to handle the offset field. This eliminates
duplicated logic for LEB128 encoding and fixup creation for symbolic
offsets.
Summary of changes:
- TableGen: Updated ATOMIC multiclasses and patterns to use the new order.
- MCCodeEmitter: Simplified encodeMemArg and added support for RMW acqrel.
- AsmParser: Updated to produce operands in the correct order for matching.
- InstPrinter: Added support for printing RMW acqrel orderings.
---
.../AsmParser/WebAssemblyAsmParser.cpp | 294 +-----------------
.../MCTargetDesc/WebAssemblyInstPrinter.cpp | 1 +
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 38 +--
.../WebAssembly/WebAssemblyInstrAtomics.td | 80 ++---
4 files changed, 51 insertions(+), 362 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 3c893d3d15b3f..a23e611810b5a 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -513,12 +513,10 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
// index. We need to avoid parsing an extra alignment operand for the
// lane index.
auto IsLoadStoreLane = InstName.contains("_lane");
- if (IsLoadStoreLane && Operands.size() == 4)
+ if (IsLoadStoreLane && Operands.size() == 4) {
return false;
+ }
// Alignment not specified (or atomics, must use default alignment).
- // We can't just call WebAssembly::GetDefaultP2Align since we don't have
- // an opcode until after the assembly matcher, so set a default to fix
- // up later.
auto Tok = Lexer.getTok();
Operands.push_back(std::make_unique<WebAssemblyOperand>(
Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
@@ -527,7 +525,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
if (!parseMemOrderMaybe(Operands)) {
auto Tok = Lexer.getTok();
Operands.push_back(std::make_unique<WebAssemblyOperand>(
- Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
+ Tok.getLoc(), Tok.getEndLoc(),
+ WebAssemblyOperand::IntOp{wasm::WASM_MEM_ORDER_SEQ_CST}));
}
}
}
@@ -680,7 +679,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
if (!parseMemOrderMaybe(Operands)) {
auto Tok = Lexer.getTok();
Operands.push_back(std::make_unique<WebAssemblyOperand>(
- Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
+ Tok.getLoc(), Tok.getEndLoc(),
+ WebAssemblyOperand::IntOp{wasm::WASM_MEM_ORDER_SEQ_CST}));
}
} else if (Name == "end_loop") {
if (pop(Name, Loop))
@@ -1186,280 +1186,6 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
}
}
-bool isAtomic(unsigned Opc) {
- switch (Opc) {
- case WebAssembly::MEMORY_ATOMIC_NOTIFY_A32:
- case WebAssembly::MEMORY_ATOMIC_NOTIFY_A32_S:
- case WebAssembly::MEMORY_ATOMIC_NOTIFY_A64:
- case WebAssembly::MEMORY_ATOMIC_NOTIFY_A64_S:
- case WebAssembly::MEMORY_ATOMIC_WAIT32_A32:
- case WebAssembly::MEMORY_ATOMIC_WAIT32_A32_S:
- case WebAssembly::MEMORY_ATOMIC_WAIT32_A64:
- case WebAssembly::MEMORY_ATOMIC_WAIT32_A64_S:
- case WebAssembly::MEMORY_ATOMIC_WAIT64_A32:
- case WebAssembly::MEMORY_ATOMIC_WAIT64_A32_S:
- case WebAssembly::MEMORY_ATOMIC_WAIT64_A64:
- case WebAssembly::MEMORY_ATOMIC_WAIT64_A64_S:
- case WebAssembly::ATOMIC_FENCE:
- case WebAssembly::ATOMIC_FENCE_S:
- case WebAssembly::ATOMIC_LOAD16_U_I32_A32:
- case WebAssembly::ATOMIC_LOAD16_U_I32_A32_S:
- case WebAssembly::ATOMIC_LOAD16_U_I32_A64:
- case WebAssembly::ATOMIC_LOAD16_U_I32_A64_S:
- case WebAssembly::ATOMIC_LOAD16_U_I64_A32:
- case WebAssembly::ATOMIC_LOAD16_U_I64_A32_S:
- case WebAssembly::ATOMIC_LOAD16_U_I64_A64:
- case WebAssembly::ATOMIC_LOAD16_U_I64_A64_S:
- case WebAssembly::ATOMIC_LOAD32_U_I64_A32:
- case WebAssembly::ATOMIC_LOAD32_U_I64_A32_S:
- case WebAssembly::ATOMIC_LOAD32_U_I64_A64:
- case WebAssembly::ATOMIC_LOAD32_U_I64_A64_S:
- case WebAssembly::ATOMIC_LOAD8_U_I32_A32:
- case WebAssembly::ATOMIC_LOAD8_U_I32_A32_S:
- case WebAssembly::ATOMIC_LOAD8_U_I32_A64:
- case WebAssembly::ATOMIC_LOAD8_U_I32_A64_S:
- case WebAssembly::ATOMIC_LOAD8_U_I64_A32:
- case WebAssembly::ATOMIC_LOAD8_U_I64_A32_S:
- case WebAssembly::ATOMIC_LOAD8_U_I64_A64:
- case WebAssembly::ATOMIC_LOAD8_U_I64_A64_S:
- case WebAssembly::ATOMIC_LOAD_I32_A32:
- case WebAssembly::ATOMIC_LOAD_I32_A32_S:
- case WebAssembly::ATOMIC_LOAD_I32_A64:
- case WebAssembly::ATOMIC_LOAD_I32_A64_S:
- case WebAssembly::ATOMIC_LOAD_I64_A32:
- case WebAssembly::ATOMIC_LOAD_I64_A32_S:
- case WebAssembly::ATOMIC_LOAD_I64_A64:
- case WebAssembly::ATOMIC_LOAD_I64_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_ADD_I32_A32:
- case WebAssembly::ATOMIC_RMW16_U_ADD_I32_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_ADD_I32_A64:
- case WebAssembly::ATOMIC_RMW16_U_ADD_I32_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_ADD_I64_A32:
- case WebAssembly::ATOMIC_RMW16_U_ADD_I64_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_ADD_I64_A64:
- case WebAssembly::ATOMIC_RMW16_U_ADD_I64_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_AND_I32_A32:
- case WebAssembly::ATOMIC_RMW16_U_AND_I32_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_AND_I32_A64:
- case WebAssembly::ATOMIC_RMW16_U_AND_I32_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_AND_I64_A32:
- case WebAssembly::ATOMIC_RMW16_U_AND_I64_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_AND_I64_A64:
- case WebAssembly::ATOMIC_RMW16_U_AND_I64_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I32_A32:
- case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I32_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I32_A64:
- case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I32_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I64_A32:
- case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I64_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I64_A64:
- case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I64_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_OR_I32_A32:
- case WebAssembly::ATOMIC_RMW16_U_OR_I32_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_OR_I32_A64:
- case WebAssembly::ATOMIC_RMW16_U_OR_I32_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_OR_I64_A32:
- case WebAssembly::ATOMIC_RMW16_U_OR_I64_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_OR_I64_A64:
- case WebAssembly::ATOMIC_RMW16_U_OR_I64_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_SUB_I32_A32:
- case WebAssembly::ATOMIC_RMW16_U_SUB_I32_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_SUB_I32_A64:
- case WebAssembly::ATOMIC_RMW16_U_SUB_I32_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_SUB_I64_A32:
- case WebAssembly::ATOMIC_RMW16_U_SUB_I64_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_SUB_I64_A64:
- case WebAssembly::ATOMIC_RMW16_U_SUB_I64_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_XCHG_I32_A32:
- case WebAssembly::ATOMIC_RMW16_U_XCHG_I32_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_XCHG_I32_A64:
- case WebAssembly::ATOMIC_RMW16_U_XCHG_I32_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_XCHG_I64_A32:
- case WebAssembly::ATOMIC_RMW16_U_XCHG_I64_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_XCHG_I64_A64:
- case WebAssembly::ATOMIC_RMW16_U_XCHG_I64_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_XOR_I32_A32:
- case WebAssembly::ATOMIC_RMW16_U_XOR_I32_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_XOR_I32_A64:
- case WebAssembly::ATOMIC_RMW16_U_XOR_I32_A64_S:
- case WebAssembly::ATOMIC_RMW16_U_XOR_I64_A32:
- case WebAssembly::ATOMIC_RMW16_U_XOR_I64_A32_S:
- case WebAssembly::ATOMIC_RMW16_U_XOR_I64_A64:
- case WebAssembly::ATOMIC_RMW16_U_XOR_I64_A64_S:
- case WebAssembly::ATOMIC_RMW32_U_ADD_I64_A32:
- case WebAssembly::ATOMIC_RMW32_U_ADD_I64_A32_S:
- case WebAssembly::ATOMIC_RMW32_U_ADD_I64_A64:
- case WebAssembly::ATOMIC_RMW32_U_ADD_I64_A64_S:
- case WebAssembly::ATOMIC_RMW32_U_AND_I64_A32:
- case WebAssembly::ATOMIC_RMW32_U_AND_I64_A32_S:
- case WebAssembly::ATOMIC_RMW32_U_AND_I64_A64:
- case WebAssembly::ATOMIC_RMW32_U_AND_I64_A64_S:
- case WebAssembly::ATOMIC_RMW32_U_CMPXCHG_I64_A32:
- case WebAssembly::ATOMIC_RMW32_U_CMPXCHG_I64_A32_S:
- case WebAssembly::ATOMIC_RMW32_U_CMPXCHG_I64_A64:
- case WebAssembly::ATOMIC_RMW32_U_CMPXCHG_I64_A64_S:
- case WebAssembly::ATOMIC_RMW32_U_OR_I64_A32:
- case WebAssembly::ATOMIC_RMW32_U_OR_I64_A32_S:
- case WebAssembly::ATOMIC_RMW32_U_OR_I64_A64:
- case WebAssembly::ATOMIC_RMW32_U_OR_I64_A64_S:
- case WebAssembly::ATOMIC_RMW32_U_SUB_I64_A32:
- case WebAssembly::ATOMIC_RMW32_U_SUB_I64_A32_S:
- case WebAssembly::ATOMIC_RMW32_U_SUB_I64_A64:
- case WebAssembly::ATOMIC_RMW32_U_SUB_I64_A64_S:
- case WebAssembly::ATOMIC_RMW32_U_XCHG_I64_A32:
- case WebAssembly::ATOMIC_RMW32_U_XCHG_I64_A32_S:
- case WebAssembly::ATOMIC_RMW32_U_XCHG_I64_A64:
- case WebAssembly::ATOMIC_RMW32_U_XCHG_I64_A64_S:
- case WebAssembly::ATOMIC_RMW32_U_XOR_I64_A32:
- case WebAssembly::ATOMIC_RMW32_U_XOR_I64_A32_S:
- case WebAssembly::ATOMIC_RMW32_U_XOR_I64_A64:
- case WebAssembly::ATOMIC_RMW32_U_XOR_I64_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_ADD_I32_A32:
- case WebAssembly::ATOMIC_RMW8_U_ADD_I32_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_ADD_I32_A64:
- case WebAssembly::ATOMIC_RMW8_U_ADD_I32_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_ADD_I64_A32:
- case WebAssembly::ATOMIC_RMW8_U_ADD_I64_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_ADD_I64_A64:
- case WebAssembly::ATOMIC_RMW8_U_ADD_I64_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_AND_I32_A32:
- case WebAssembly::ATOMIC_RMW8_U_AND_I32_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_AND_I32_A64:
- case WebAssembly::ATOMIC_RMW8_U_AND_I32_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_AND_I64_A32:
- case WebAssembly::ATOMIC_RMW8_U_AND_I64_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_AND_I64_A64:
- case WebAssembly::ATOMIC_RMW8_U_AND_I64_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I32_A32:
- case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I32_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I32_A64:
- case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I32_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I64_A32:
- case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I64_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I64_A64:
- case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I64_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_OR_I32_A32:
- case WebAssembly::ATOMIC_RMW8_U_OR_I32_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_OR_I32_A64:
- case WebAssembly::ATOMIC_RMW8_U_OR_I32_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_OR_I64_A32:
- case WebAssembly::ATOMIC_RMW8_U_OR_I64_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_OR_I64_A64:
- case WebAssembly::ATOMIC_RMW8_U_OR_I64_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_SUB_I32_A32:
- case WebAssembly::ATOMIC_RMW8_U_SUB_I32_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_SUB_I32_A64:
- case WebAssembly::ATOMIC_RMW8_U_SUB_I32_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_SUB_I64_A32:
- case WebAssembly::ATOMIC_RMW8_U_SUB_I64_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_SUB_I64_A64:
- case WebAssembly::ATOMIC_RMW8_U_SUB_I64_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_XCHG_I32_A32:
- case WebAssembly::ATOMIC_RMW8_U_XCHG_I32_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_XCHG_I32_A64:
- case WebAssembly::ATOMIC_RMW8_U_XCHG_I32_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_XCHG_I64_A32:
- case WebAssembly::ATOMIC_RMW8_U_XCHG_I64_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_XCHG_I64_A64:
- case WebAssembly::ATOMIC_RMW8_U_XCHG_I64_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_XOR_I32_A32:
- case WebAssembly::ATOMIC_RMW8_U_XOR_I32_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_XOR_I32_A64:
- case WebAssembly::ATOMIC_RMW8_U_XOR_I32_A64_S:
- case WebAssembly::ATOMIC_RMW8_U_XOR_I64_A32:
- case WebAssembly::ATOMIC_RMW8_U_XOR_I64_A32_S:
- case WebAssembly::ATOMIC_RMW8_U_XOR_I64_A64:
- case WebAssembly::ATOMIC_RMW8_U_XOR_I64_A64_S:
- case WebAssembly::ATOMIC_RMW_ADD_I32_A32:
- case WebAssembly::ATOMIC_RMW_ADD_I32_A32_S:
- case WebAssembly::ATOMIC_RMW_ADD_I32_A64:
- case WebAssembly::ATOMIC_RMW_ADD_I32_A64_S:
- case WebAssembly::ATOMIC_RMW_ADD_I64_A32:
- case WebAssembly::ATOMIC_RMW_ADD_I64_A32_S:
- case WebAssembly::ATOMIC_RMW_ADD_I64_A64:
- case WebAssembly::ATOMIC_RMW_ADD_I64_A64_S:
- case WebAssembly::ATOMIC_RMW_AND_I32_A32:
- case WebAssembly::ATOMIC_RMW_AND_I32_A32_S:
- case WebAssembly::ATOMIC_RMW_AND_I32_A64:
- case WebAssembly::ATOMIC_RMW_AND_I32_A64_S:
- case WebAssembly::ATOMIC_RMW_AND_I64_A32:
- case WebAssembly::ATOMIC_RMW_AND_I64_A32_S:
- case WebAssembly::ATOMIC_RMW_AND_I64_A64:
- case WebAssembly::ATOMIC_RMW_AND_I64_A64_S:
- case WebAssembly::ATOMIC_RMW_CMPXCHG_I32_A32:
- case WebAssembly::ATOMIC_RMW_CMPXCHG_I32_A32_S:
- case WebAssembly::ATOMIC_RMW_CMPXCHG_I32_A64:
- case WebAssembly::ATOMIC_RMW_CMPXCHG_I32_A64_S:
- case WebAssembly::ATOMIC_RMW_CMPXCHG_I64_A32:
- case WebAssembly::ATOMIC_RMW_CMPXCHG_I64_A32_S:
- case WebAssembly::ATOMIC_RMW_CMPXCHG_I64_A64:
- case WebAssembly::ATOMIC_RMW_CMPXCHG_I64_A64_S:
- case WebAssembly::ATOMIC_RMW_OR_I32_A32:
- case WebAssembly::ATOMIC_RMW_OR_I32_A32_S:
- case WebAssembly::ATOMIC_RMW_OR_I32_A64:
- case WebAssembly::ATOMIC_RMW_OR_I32_A64_S:
- case WebAssembly::ATOMIC_RMW_OR_I64_A32:
- case WebAssembly::ATOMIC_RMW_OR_I64_A32_S:
- case WebAssembly::ATOMIC_RMW_OR_I64_A64:
- case WebAssembly::ATOMIC_RMW_OR_I64_A64_S:
- case WebAssembly::ATOMIC_RMW_SUB_I32_A32:
- case WebAssembly::ATOMIC_RMW_SUB_I32_A32_S:
- case WebAssembly::ATOMIC_RMW_SUB_I32_A64:
- case WebAssembly::ATOMIC_RMW_SUB_I32_A64_S:
- case WebAssembly::ATOMIC_RMW_SUB_I64_A32:
- case WebAssembly::ATOMIC_RMW_SUB_I64_A32_S:
- case WebAssembly::ATOMIC_RMW_SUB_I64_A64:
- case WebAssembly::ATOMIC_RMW_SUB_I64_A64_S:
- case WebAssembly::ATOMIC_RMW_XCHG_I32_A32:
- case WebAssembly::ATOMIC_RMW_XCHG_I32_A32_S:
- case WebAssembly::ATOMIC_RMW_XCHG_I32_A64:
- case WebAssembly::ATOMIC_RMW_XCHG_I32_A64_S:
- case WebAssembly::ATOMIC_RMW_XCHG_I64_A32:
- case WebAssembly::ATOMIC_RMW_XCHG_I64_A32_S:
- case WebAssembly::ATOMIC_RMW_XCHG_I64_A64:
- case WebAssembly::ATOMIC_RMW_XCHG_I64_A64_S:
- case WebAssembly::ATOMIC_RMW_XOR_I32_A32:
- case WebAssembly::ATOMIC_RMW_XOR_I32_A32_S:
- case WebAssembly::ATOMIC_RMW_XOR_I32_A64:
- case WebAssembly::ATOMIC_RMW_XOR_I32_A64_S:
- case WebAssembly::ATOMIC_RMW_XOR_I64_A32:
- case WebAssembly::ATOMIC_RMW_XOR_I64_A32_S:
- case WebAssembly::ATOMIC_RMW_XOR_I64_A64:
- case WebAssembly::ATOMIC_RMW_XOR_I64_A64_S:
- case WebAssembly::ATOMIC_STORE16_I32_A32:
- case WebAssembly::ATOMIC_STORE16_I32_A32_S:
- case WebAssembly::ATOMIC_STORE16_I32_A64:
- case WebAssembly::ATOMIC_STORE16_I32_A64_S:
- case WebAssembly::ATOMIC_STORE16_I64_A32:
- case WebAssembly::ATOMIC_STORE16_I64_A32_S:
- case WebAssembly::ATOMIC_STORE16_I64_A64:
- case WebAssembly::ATOMIC_STORE16_I64_A64_S:
- case WebAssembly::ATOMIC_STORE32_I64_A32:
- case WebAssembly::ATOMIC_STORE32_I64_A32_S:
- case WebAssembly::ATOMIC_STORE32_I64_A64:
- case WebAssembly::ATOMIC_STORE32_I64_A64_S:
- case WebAssembly::ATOMIC_STORE8_I32_A32:
- case WebAssembly::ATOMIC_STORE8_I32_A32_S:
- case WebAssembly::ATOMIC_STORE8_I32_A64:
- case WebAssembly::ATOMIC_STORE8_I32_A64_S:
- case WebAssembly::ATOMIC_STORE8_I64_A32:
- case WebAssembly::ATOMIC_STORE8_I64_A32_S:
- case WebAssembly::ATOMIC_STORE8_I64_A64:
- case WebAssembly::ATOMIC_STORE8_I64_A64_S:
- case WebAssembly::ATOMIC_STORE_I32_A32:
- case WebAssembly::ATOMIC_STORE_I32_A32_S:
- case WebAssembly::ATOMIC_STORE_I32_A64:
- case WebAssembly::ATOMIC_STORE_I32_A64_S:
- case WebAssembly::ATOMIC_STORE_I64_A32:
- case WebAssembly::ATOMIC_STORE_I64_A32_S:
- case WebAssembly::ATOMIC_STORE_I64_A64:
- case WebAssembly::ATOMIC_STORE_I64_A64_S:
- return true;
- default:
- return false;
- }
-}
-
bool matchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
OperandVector &Operands, MCStreamer &Out,
uint64_t &ErrorInfo,
@@ -1489,14 +1215,6 @@ bool isAtomic(unsigned Opc) {
Inst.setOpcode(Opc64);
}
}
- // Fix unknown memory ordering operands.
- if (isAtomic(Inst.getOpcode())) {
- for (unsigned i = 0; i < Inst.getNumOperands(); ++i) {
- auto &Op = Inst.getOperand(i);
- if (Op.isImm() && Op.getImm() == -1)
- Op.setImm(wasm::WASM_MEM_ORDER_SEQ_CST);
- }
- }
if (!SkipTypeCheck)
TC.typeCheck(IDLoc, Inst, Operands);
Out.emitInstruction(Inst, getSTI());
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 2e30ccb586919..3edd4929f81c2 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -380,6 +380,7 @@ void WebAssemblyInstPrinter::printWebAssemblyMemOrderOperand(const MCInst *MI,
return;
switch (Imm) {
+ case wasm::WASM_MEM_ORDER_RMW_ACQ_REL:
case wasm::WASM_MEM_ORDER_ACQ_REL:
O << " acqrel";
break;
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index ebed623155b53..0f377b55adc60 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -82,24 +82,16 @@ void WebAssemblyMCCodeEmitter::encodeMemArg(
SmallSet<unsigned, 4> &HandledOperands,
SmallVectorImpl<MCFixup> &Fixups, uint64_t Start) const {
unsigned P2AlignIdx = I;
- std::optional<unsigned> OffsetIdx;
std::optional<unsigned> MemOrderIdx;
- for (unsigned J = 0; J < MI.getNumOperands(); ++J) {
- if (J < Desc.getNumOperands()) {
- auto OT = Desc.operands()[J].OperandType;
- if (OT == WebAssembly::OPERAND_OFFSET32 ||
- OT == WebAssembly::OPERAND_OFFSET64)
- OffsetIdx = J;
- else if (OT == WebAssembly::OPERAND_MEMORDER)
- MemOrderIdx = J;
- }
- }
+ if (I + 1 < Desc.getNumOperands() &&
+ Desc.operands()[I + 1].OperandType == WebAssembly::OPERAND_MEMORDER)
+ MemOrderIdx = I + 1;
uint64_t P2Align = MI.getOperand(P2AlignIdx).getImm();
uint8_t Order = wasm::WASM_MEM_ORDER_SEQ_CST;
- // Memory instructions always have an ordering, but if it's SEQ_CST then we
+ // Atomic instructions always have an ordering, but if it's SEQ_CST then we
// don't use the shared-everything encoding (even if shared everything is
// enabled) because the original encoding is smaller.
if (MemOrderIdx) {
@@ -124,28 +116,6 @@ void WebAssemblyMCCodeEmitter::encodeMemArg(
// We handled the MemOrder operand, even if we didn't encode it explicitly
if (MemOrderIdx)
HandledOperands.insert(*MemOrderIdx);
-
- if (OffsetIdx) {
- const MCOperand &MO = MI.getOperand(*OffsetIdx);
- if (MO.isImm()) {
- if (Desc.operands()[*OffsetIdx].OperandType == WebAssembly::OPERAND_OFFSET32)
- encodeULEB128(uint32_t(MO.getImm()), OS);
- else
- encodeULEB128(uint64_t(MO.getImm()), OS);
- } else {
- assert(MO.isExpr());
- llvm::MCFixupKind FixupKind =
- Desc.operands()[*OffsetIdx].OperandType == WebAssembly::OPERAND_OFFSET32
- ? WebAssembly::fixup_uleb128_i32
- : WebAssembly::fixup_uleb128_i64;
- raw_svector_ostream &SOS = static_cast<raw_svector_ostream &>(OS);
- Fixups.push_back(
- MCFixup::create(SOS.tell() - Start, MO.getExpr(), FixupKind));
- ++MCNumFixups;
- encodeULEB128(0, OS, FixupKind == WebAssembly::fixup_uleb128_i32 ? 5 : 10);
- }
- HandledOperands.insert(*OffsetIdx);
- }
}
void WebAssemblyMCCodeEmitter::encodeInstruction(
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
index 70f37dd1386fa..a7f336c67a167 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
@@ -35,43 +35,43 @@ multiclass ATOMIC_NRI<dag oops, dag iops, list<dag> pattern, string asmstr = "",
let hasSideEffects = 1 in {
defm MEMORY_ATOMIC_NOTIFY_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, I32:$count),
- (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, I32:$count),
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
"memory.atomic.notify \t$dst, ${off}(${addr})${p2align}${order}, $count",
"memory.atomic.notify \t${off}${p2align}${order}", 0x00, false>;
defm MEMORY_ATOMIC_NOTIFY_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, I32:$count),
- (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, I32:$count),
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
"memory.atomic.notify \t$dst, ${off}(${addr})${p2align}${order}, $count",
"memory.atomic.notify \t${off}${p2align}${order}", 0x00, true>;
let mayLoad = 1 in {
defm MEMORY_ATOMIC_WAIT32_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, I32:$exp,
+ (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, I32:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
"memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
"memory.atomic.wait32 \t${off}${p2align}${order}", 0x01, false>;
defm MEMORY_ATOMIC_WAIT32_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, I32:$exp,
+ (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, I32:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
"memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
"memory.atomic.wait32 \t${off}${p2align}${order}", 0x01, true>;
defm MEMORY_ATOMIC_WAIT64_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, I64:$exp,
+ (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, I64:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
"memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
"memory.atomic.wait64 \t${off}${p2align}${order}", 0x02, false>;
defm MEMORY_ATOMIC_WAIT64_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, I64:$exp,
+ (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, I64:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
"memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
"memory.atomic.wait64 \t${off}${p2align}${order}", 0x02, true>;
} // mayLoad = 1
@@ -79,22 +79,22 @@ defm MEMORY_ATOMIC_WAIT64_A64 :
def NotifyPat_A32 :
Pat<(i32 (int_wasm_memory_atomic_notify (AddrOps32 offset32_op:$offset, I32:$addr), I32:$count)),
- (MEMORY_ATOMIC_NOTIFY_A32 0, $offset, 0, $addr, $count)>,
+ (MEMORY_ATOMIC_NOTIFY_A32 0, 0, $offset, $addr, $count)>,
Requires<[HasAddr32, HasAtomics]>;
def NotifyPat_A64 :
Pat<(i32 (int_wasm_memory_atomic_notify (AddrOps64 offset64_op:$offset, I64:$addr), I32:$count)),
- (MEMORY_ATOMIC_NOTIFY_A64 0, $offset, 0, $addr, $count)>,
+ (MEMORY_ATOMIC_NOTIFY_A64 0, 0, $offset, $addr, $count)>,
Requires<[HasAddr64, HasAtomics]>;
multiclass WaitPat<ValueType ty, Intrinsic kind, string inst> {
def WaitPat_A32 :
Pat<(i32 (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$exp, I64:$timeout)),
- (!cast<NI>(inst#_A32) 0, $offset, 0, $addr, $exp, $timeout)>,
+ (!cast<NI>(inst#_A32) 0, 0, $offset, $addr, $exp, $timeout)>,
Requires<[HasAddr32, HasAtomics]>;
def WaitPat_A64 :
Pat<(i32 (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$exp, I64:$timeout)),
- (!cast<NI>(inst#_A64) 0, $offset, 0, $addr, $exp, $timeout)>,
+ (!cast<NI>(inst#_A64) 0, 0, $offset, $addr, $exp, $timeout)>,
Requires<[HasAddr64, HasAtomics]>;
}
@@ -121,14 +121,14 @@ defm ATOMIC_FENCE : ATOMIC_NRI<(outs), (ins MemOrder:$order), [],
multiclass WebAssemblyAtomicLoad<WebAssemblyRegClass rc, string name, int Opcode> {
let mayLoad = 1, UseNamedOperandTable = 1 in {
defm "_A32": I<(outs rc:$dst),
- (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr),
- (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order),
+ (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr),
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off),
[], !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}"),
!strconcat(name, "\t${off}${p2align}${order}"), Opcode, false>,
Requires<[HasAtomics]>;
defm "_A64": I<(outs rc:$dst),
- (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr),
- (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order),
+ (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr),
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off),
[], !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}"),
!strconcat(name, "\t${off}${p2align}${order}"), Opcode, true>,
Requires<[HasAtomics]>;
@@ -141,10 +141,10 @@ multiclass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> {
multiclass AtomicLoadPat<ValueType ty, SDPatternOperator kind, string Name> {
def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr))),
- (!cast<NI>(Name # "_A32") 0, offset32_op:$offset, 0, I32:$addr)>,
+ (!cast<NI>(Name # "_A32") 0, 0, offset32_op:$offset, I32:$addr)>,
Requires<[HasAddr32, HasAtomics]>;
def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr))),
- (!cast<NI>(Name # "_A64") 0, offset64_op:$offset, 0, I64:$addr)>,
+ (!cast<NI>(Name # "_A64") 0, 0, offset64_op:$offset, I64:$addr)>,
Requires<[HasAddr64, HasAtomics]>;
}
@@ -212,14 +212,14 @@ defm : AtomicLoadPat<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
multiclass WebAssemblyAtomicStore<WebAssemblyRegClass rc, string name, int Opcode> {
let mayStore = 1, UseNamedOperandTable = 1 in {
defm "_A32" : I<(outs),
- (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, rc:$val),
- (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, rc:$val),
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
!strconcat(name, "\t${off}(${addr})${p2align}${order}, $val"),
!strconcat(name, "\t${off}${p2align}${order}"), Opcode, false>,
Requires<[HasAtomics]>;
defm "_A64" : I<(outs),
- (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, rc:$val),
- (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, rc:$val),
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
!strconcat(name, "\t${off}(${addr})${p2align}${order}, $val"),
!strconcat(name, "\t${off}${p2align}${order}"), Opcode, true>,
Requires<[HasAtomics]>;
@@ -241,10 +241,10 @@ defm ATOMIC_STORE_I64 : AtomicStore<I64, "i64.atomic.store", 0x18>;
multiclass AStorePat<ValueType ty, PatFrag kind, string inst> {
def : Pat<(kind ty:$val, (AddrOps32 offset32_op:$offset, I32:$addr)),
- (!cast<NI>(inst#_A32) 0, $offset, 0, $addr, $val)>,
+ (!cast<NI>(inst#_A32) 0, 0, $offset, $addr, $val)>,
Requires<[HasAddr32, HasAtomics]>;
def : Pat<(kind ty:$val, (AddrOps64 offset64_op:$offset, I64:$addr)),
- (!cast<NI>(inst#_A64) 0, $offset, 0, $addr, $val)>,
+ (!cast<NI>(inst#_A64) 0, 0, $offset, $addr, $val)>,
Requires<[HasAddr64, HasAtomics]>;
}
defm : AStorePat<i32, atomic_store_32, "ATOMIC_STORE_I32">;
@@ -284,14 +284,14 @@ multiclass WebAssemblyBinRMW<WebAssemblyRegClass rc, string name,
int atomic_op> {
defm "_A32" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, rc:$val),
- (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, rc:$val),
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
!strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $val"),
!strconcat(name, "\t${off}${p2align}${order}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, rc:$val),
- (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, rc:$val),
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
!strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $val"),
!strconcat(name, "\t${off}${p2align}${order}"), atomic_op, true>;
}
@@ -378,10 +378,10 @@ defm ATOMIC_RMW32_U_XCHG_I64 :
multiclass BinRMWPat<ValueType ty, PatFrag kind, string inst> {
def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$val)),
- (!cast<NI>(inst#_A32) 0, $offset, 0, $addr, $val)>,
+ (!cast<NI>(inst#_A32) 0, 0, $offset, $addr, $val)>,
Requires<[HasAddr32, HasAtomics]>;
def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$val)),
- (!cast<NI>(inst#_A64) 0, $offset, 0, $addr, $val)>,
+ (!cast<NI>(inst#_A64) 0, 0, $offset, $addr, $val)>,
Requires<[HasAddr64, HasAtomics]>;
}
@@ -488,16 +488,16 @@ multiclass WebAssemblyTerRMW<WebAssemblyRegClass rc, string name,
int atomic_op> {
defm "_A32" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order, I32:$addr, rc:$exp,
+ (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, rc:$exp,
rc:$new_),
- (outs), (ins P2Align:$p2align, offset32_op:$off, MemOrder:$order), [],
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
!strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $exp, $new_"),
!strconcat(name, "\t${off}${p2align}${order}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order, I64:$addr, rc:$exp,
+ (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, rc:$exp,
rc:$new_),
- (outs), (ins P2Align:$p2align, offset64_op:$off, MemOrder:$order), [],
+ (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
!strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $exp, $new_"),
!strconcat(name, "\t${off}${p2align}${order}"), atomic_op, true>;
}
@@ -519,10 +519,10 @@ defm ATOMIC_RMW32_U_CMPXCHG_I64 :
multiclass TerRMWPat<ValueType ty, PatFrag kind, string inst> {
def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$exp, ty:$new)),
- (!cast<NI>(inst#_A32) 0, $offset, 0, $addr, $exp, $new)>,
+ (!cast<NI>(inst#_A32) 0, 0, $offset, $addr, $exp, $new)>,
Requires<[HasAddr32, HasAtomics]>;
def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$exp, ty:$new)),
- (!cast<NI>(inst#_A64) 0, $offset, 0, $addr, $exp, $new)>,
+ (!cast<NI>(inst#_A64) 0, 0, $offset, $addr, $exp, $new)>,
Requires<[HasAddr64, HasAtomics]>;
}
>From c29cbda78e736f4f65b16c5f3e210aefefc9724b Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 26 Feb 2026 00:36:45 +0000
Subject: [PATCH 10/22] Reverse order of operands in text format
Also make parseMemOrderMaybe consistent with similar functions
---
.../AsmParser/WebAssemblyAsmParser.cpp | 29 ++++---
.../MCTargetDesc/WebAssemblyInstPrinter.cpp | 11 ++-
.../WebAssembly/WebAssemblyInstrAtomics.td | 58 ++++++-------
llvm/test/MC/WebAssembly/atomics-encodings.s | 2 +-
.../MC/WebAssembly/atomics-orderings-errors.s | 8 +-
llvm/test/MC/WebAssembly/atomics-orderings.s | 85 ++++++++++---------
6 files changed, 101 insertions(+), 92 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index a23e611810b5a..3dc516cbe414e 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -475,20 +475,20 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
bool parseMemOrderMaybe(OperandVector &Operands) {
auto &Tok = Lexer.getTok();
if (Tok.isNot(AsmToken::Identifier))
- return false;
+ return true;
StringRef S = Tok.getString();
int64_t Order = StringSwitch<int64_t>(S)
.Case("acqrel", wasm::WASM_MEM_ORDER_ACQ_REL)
.Case("seqcst", wasm::WASM_MEM_ORDER_SEQ_CST)
.Default(-1);
if (Order == -1)
- return false;
+ return true;
if (!STI->checkFeatures("+shared-everything"))
return error("memory ordering requires shared-everything feature: ", Tok);
Operands.push_back(std::make_unique<WebAssemblyOperand>(
Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{Order}));
Parser.Lex();
- return true;
+ return false;
}
bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {
@@ -513,22 +513,13 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
// index. We need to avoid parsing an extra alignment operand for the
// lane index.
auto IsLoadStoreLane = InstName.contains("_lane");
- if (IsLoadStoreLane && Operands.size() == 4) {
+ if (IsLoadStoreLane && Operands.size() == 4)
return false;
- }
// Alignment not specified (or atomics, must use default alignment).
auto Tok = Lexer.getTok();
Operands.push_back(std::make_unique<WebAssemblyOperand>(
Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
}
- if (IsAtomic && !InstName.contains("fence")) {
- if (!parseMemOrderMaybe(Operands)) {
- auto Tok = Lexer.getTok();
- Operands.push_back(std::make_unique<WebAssemblyOperand>(
- Tok.getLoc(), Tok.getEndLoc(),
- WebAssemblyOperand::IntOp{wasm::WASM_MEM_ORDER_SEQ_CST}));
- }
- }
}
return false;
}
@@ -676,7 +667,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
if (pop(Name, Try))
return true;
} else if (Name == "atomic.fence") {
- if (!parseMemOrderMaybe(Operands)) {
+ if(parseMemOrderMaybe(Operands)) {
auto Tok = Lexer.getTok();
Operands.push_back(std::make_unique<WebAssemblyOperand>(
Tok.getLoc(), Tok.getEndLoc(),
@@ -706,6 +697,16 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
ExpectFuncType = true;
}
+ bool IsAtomic = Name.contains("atomic.");
+ if (IsAtomic && Name != "atomic.fence") {
+ if(parseMemOrderMaybe(Operands)) {
+ auto Tok = Lexer.getTok();
+ Operands.push_back(std::make_unique<WebAssemblyOperand>(
+ Tok.getLoc(), Tok.getEndLoc(),
+ WebAssemblyOperand::IntOp{wasm::WASM_MEM_ORDER_SEQ_CST}));
+ }
+ }
+
// Returns true if the next tokens are a catch clause
auto PeekCatchList = [&]() {
if (Lexer.isNot(AsmToken::LParen))
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 3edd4929f81c2..3ce881b119682 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -375,17 +375,20 @@ void WebAssemblyInstPrinter::printWebAssemblyMemOrderOperand(const MCInst *MI,
unsigned OpNo,
raw_ostream &O) {
int64_t Imm = MI->getOperand(OpNo).getImm();
- if (Imm == wasm::WASM_MEM_ORDER_SEQ_CST &&
- (!STI || !STI->getFeatureBits()[WebAssembly::FeatureSharedEverything]))
+ unsigned Opcode = MI->getOpcode();
+ bool IsFence = Opcode == WebAssembly::ATOMIC_FENCE ||
+ Opcode == WebAssembly::ATOMIC_FENCE_S;
+
+ if (Imm == wasm::WASM_MEM_ORDER_SEQ_CST && !IsFence)
return;
switch (Imm) {
case wasm::WASM_MEM_ORDER_RMW_ACQ_REL:
case wasm::WASM_MEM_ORDER_ACQ_REL:
- O << " acqrel";
+ O << "acqrel";
break;
case wasm::WASM_MEM_ORDER_SEQ_CST:
- O << " seqcst";
+ O << "seqcst";
break;
default:
llvm_unreachable("Unknown memory ordering");
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
index a7f336c67a167..1d6ebd9e62d18 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
@@ -37,43 +37,43 @@ defm MEMORY_ATOMIC_NOTIFY_A32 :
ATOMIC_I<(outs I32:$dst),
(ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, I32:$count),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
- "memory.atomic.notify \t$dst, ${off}(${addr})${p2align}${order}, $count",
- "memory.atomic.notify \t${off}${p2align}${order}", 0x00, false>;
+ "memory.atomic.notify \t$dst, ${order} ${off}(${addr})${p2align}, $count",
+ "memory.atomic.notify \t${order} ${off}${p2align}", 0x00, false>;
defm MEMORY_ATOMIC_NOTIFY_A64 :
ATOMIC_I<(outs I32:$dst),
(ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, I32:$count),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
- "memory.atomic.notify \t$dst, ${off}(${addr})${p2align}${order}, $count",
- "memory.atomic.notify \t${off}${p2align}${order}", 0x00, true>;
+ "memory.atomic.notify \t$dst, ${order} ${off}(${addr})${p2align}, $count",
+ "memory.atomic.notify \t${order} ${off}${p2align}", 0x00, true>;
let mayLoad = 1 in {
defm MEMORY_ATOMIC_WAIT32_A32 :
ATOMIC_I<(outs I32:$dst),
(ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, I32:$exp,
I64:$timeout),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
- "memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
- "memory.atomic.wait32 \t${off}${p2align}${order}", 0x01, false>;
+ "memory.atomic.wait32 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
+ "memory.atomic.wait32 \t${order} ${off}${p2align}", 0x01, false>;
defm MEMORY_ATOMIC_WAIT32_A64 :
ATOMIC_I<(outs I32:$dst),
(ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, I32:$exp,
I64:$timeout),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
- "memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
- "memory.atomic.wait32 \t${off}${p2align}${order}", 0x01, true>;
+ "memory.atomic.wait32 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
+ "memory.atomic.wait32 \t${order} ${off}${p2align}", 0x01, true>;
defm MEMORY_ATOMIC_WAIT64_A32 :
ATOMIC_I<(outs I32:$dst),
(ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, I64:$exp,
I64:$timeout),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
- "memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
- "memory.atomic.wait64 \t${off}${p2align}${order}", 0x02, false>;
+ "memory.atomic.wait64 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
+ "memory.atomic.wait64 \t${order} ${off}${p2align}", 0x02, false>;
defm MEMORY_ATOMIC_WAIT64_A64 :
ATOMIC_I<(outs I32:$dst),
(ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, I64:$exp,
I64:$timeout),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
- "memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}${order}, $exp, $timeout",
- "memory.atomic.wait64 \t${off}${p2align}${order}", 0x02, true>;
+ "memory.atomic.wait64 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
+ "memory.atomic.wait64 \t${order} ${off}${p2align}", 0x02, true>;
} // mayLoad = 1
} // hasSideEffects = 1
@@ -111,7 +111,7 @@ let isPseudo = 1, hasSideEffects = 1 in
defm COMPILER_FENCE : ATOMIC_NRI<(outs), (ins), [], "compiler_fence">;
let hasSideEffects = 1 in
defm ATOMIC_FENCE : ATOMIC_NRI<(outs), (ins MemOrder:$order), [],
- "atomic.fence${order}", 0x03>;
+ "atomic.fence\t${order}", 0x03>;
} // Defs = [ARGUMENTS]
//===----------------------------------------------------------------------===//
@@ -123,14 +123,14 @@ multiclass WebAssemblyAtomicLoad<WebAssemblyRegClass rc, string name, int Opcode
defm "_A32": I<(outs rc:$dst),
(ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off),
- [], !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}"),
- !strconcat(name, "\t${off}${p2align}${order}"), Opcode, false>,
+ [], !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), Opcode, false>,
Requires<[HasAtomics]>;
defm "_A64": I<(outs rc:$dst),
(ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off),
- [], !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}"),
- !strconcat(name, "\t${off}${p2align}${order}"), Opcode, true>,
+ [], !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), Opcode, true>,
Requires<[HasAtomics]>;
}
}
@@ -214,14 +214,14 @@ multiclass WebAssemblyAtomicStore<WebAssemblyRegClass rc, string name, int Opcod
defm "_A32" : I<(outs),
(ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, rc:$val),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
- !strconcat(name, "\t${off}(${addr})${p2align}${order}, $val"),
- !strconcat(name, "\t${off}${p2align}${order}"), Opcode, false>,
+ !strconcat(name, "\t${order} ${off}(${addr})${p2align}, $val"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), Opcode, false>,
Requires<[HasAtomics]>;
defm "_A64" : I<(outs),
(ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, rc:$val),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
- !strconcat(name, "\t${off}(${addr})${p2align}${order}, $val"),
- !strconcat(name, "\t${off}${p2align}${order}"), Opcode, true>,
+ !strconcat(name, "\t${order} ${off}(${addr})${p2align}, $val"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), Opcode, true>,
Requires<[HasAtomics]>;
}
}
@@ -286,14 +286,14 @@ multiclass WebAssemblyBinRMW<WebAssemblyRegClass rc, string name,
ATOMIC_I<(outs rc:$dst),
(ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, rc:$val),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
- !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $val"),
- !strconcat(name, "\t${off}${p2align}${order}"), atomic_op, false>;
+ !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $val"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
(ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, rc:$val),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
- !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $val"),
- !strconcat(name, "\t${off}${p2align}${order}"), atomic_op, true>;
+ !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $val"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, true>;
}
defm ATOMIC_RMW_ADD_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.add", 0x1e>;
@@ -491,15 +491,15 @@ multiclass WebAssemblyTerRMW<WebAssemblyRegClass rc, string name,
(ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, rc:$exp,
rc:$new_),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
- !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $exp, $new_"),
- !strconcat(name, "\t${off}${p2align}${order}"), atomic_op, false>;
+ !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $exp, $new_"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
(ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, rc:$exp,
rc:$new_),
(outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
- !strconcat(name, "\t$dst, ${off}(${addr})${p2align}${order}, $exp, $new_"),
- !strconcat(name, "\t${off}${p2align}${order}"), atomic_op, true>;
+ !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $exp, $new_"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, true>;
}
defm ATOMIC_RMW_CMPXCHG_I32 :
diff --git a/llvm/test/MC/WebAssembly/atomics-encodings.s b/llvm/test/MC/WebAssembly/atomics-encodings.s
index aa0117d623e45..f16b5b9dab7eb 100644
--- a/llvm/test/MC/WebAssembly/atomics-encodings.s
+++ b/llvm/test/MC/WebAssembly/atomics-encodings.s
@@ -10,7 +10,7 @@ main:
# CHECK: memory.atomic.wait64 0 # encoding: [0xfe,0x02,0x03,0x00]
memory.atomic.wait64 0
- # CHECK: atomic.fence # encoding: [0xfe,0x03,0x00]
+ # CHECK: atomic.fence seqcst # encoding: [0xfe,0x03,0x00]
atomic.fence
# CHECK: i32.atomic.load 0 # encoding: [0xfe,0x10,0x02,0x00]
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings-errors.s b/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
index 43b552e57d486..573be35ef5724 100644
--- a/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
+++ b/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
@@ -6,10 +6,10 @@ main:
# CHECK: :[[@LINE+1]]:16: error: memory ordering requires shared-everything feature: acqrel
atomic.fence acqrel
- # CHECK: :[[@LINE+1]]:21: error: memory ordering requires shared-everything feature: acqrel
- i32.atomic.load 0 acqrel
+ # CHECK: :[[@LINE+1]]:19: error: memory ordering requires shared-everything feature: acqrel
+ i32.atomic.load acqrel 0
- # CHECK: :[[@LINE+1]]:24: error: memory ordering requires shared-everything feature: seqcst
- i32.atomic.rmw.add 0 seqcst
+ # CHECK: :[[@LINE+1]]:22: error: memory ordering requires shared-everything feature: seqcst
+ i32.atomic.rmw.add seqcst 0
end_function
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings.s b/llvm/test/MC/WebAssembly/atomics-orderings.s
index 59ce4e7569723..05d5057e89153 100644
--- a/llvm/test/MC/WebAssembly/atomics-orderings.s
+++ b/llvm/test/MC/WebAssembly/atomics-orderings.s
@@ -1,55 +1,60 @@
# RUN: llvm-mc -no-type-check -show-encoding -triple=wasm32-unknown-unknown -mattr=+atomics,+shared-everything < %s | FileCheck %s
-# RUN: llvm-mc -no-type-check -triple=wasm32-unknown-unknown -mattr=+atomics,+shared-everything %s -filetype=obj -o - | llvm-objdump -d --mattr=+atomics,+shared-everything - | FileCheck %s --check-prefix=DISASM
+# RUN: llvm-mc -no-type-check -triple=wasm32-unknown-unknown -mattr=+atomics,+shared-everything %s -filetype=obj -o - | llvm-objdump --no-print-imm-hex -d - | FileCheck %s --check-prefix=DISASM
+.section .text.main,"",@
main:
.functype main () -> ()
+ atomic.fence seqcst
# CHECK: atomic.fence seqcst # encoding: [0xfe,0x03,0x00]
# DISASM: atomic.fence seqcst
- atomic.fence
+
+ atomic.fence acqrel
# CHECK: atomic.fence acqrel # encoding: [0xfe,0x03,0x01]
# DISASM: atomic.fence acqrel
- atomic.fence acqrel
+
+ atomic.fence
# CHECK: atomic.fence seqcst # encoding: [0xfe,0x03,0x00]
# DISASM: atomic.fence seqcst
- atomic.fence seqcst
- # CHECK: i32.atomic.load 0 seqcst # encoding: [0xfe,0x10,0x02,0x00]
- # DISASM: i32.atomic.load 0 seqcst
+ # CHECK: i32.atomic.load 0 # encoding: [0xfe,0x10,0x02,0x00]
+ # DISASM: i32.atomic.load 0
i32.atomic.load 0
- # CHECK: i32.atomic.load 0 acqrel # encoding: [0xfe,0x10,0x22,0x01,0x00]
- # DISASM: i32.atomic.load 0 acqrel
- i32.atomic.load 0 acqrel
- # CHECK: i32.atomic.load 0 seqcst # encoding: [0xfe,0x10,0x02,0x00]
- # DISASM: i32.atomic.load 0 seqcst
- i32.atomic.load 0 seqcst
-
- # CHECK: i64.atomic.load 0 acqrel # encoding: [0xfe,0x11,0x23,0x01,0x00]
- # DISASM: i64.atomic.load 0 acqrel
- i64.atomic.load 0 acqrel
-
- # CHECK: i32.atomic.store 0 acqrel # encoding: [0xfe,0x17,0x22,0x01,0x00]
- # DISASM: i32.atomic.store 0 acqrel
- i32.atomic.store 0 acqrel
-
- # CHECK: i64.atomic.store 8 acqrel # encoding: [0xfe,0x18,0x23,0x01,0x08]
- # DISASM: i64.atomic.store 8 acqrel
- i64.atomic.store 8 acqrel
-
- # CHECK: i32.atomic.rmw.add 0 acqrel # encoding: [0xfe,0x1e,0x22,0x11,0x00]
- # DISASM: i32.atomic.rmw.add 0 acqrel
- i32.atomic.rmw.add 0 acqrel
-
- # CHECK: i64.atomic.rmw.cmpxchg 0 acqrel # encoding: [0xfe,0x49,0x23,0x11,0x00]
- # DISASM: i64.atomic.rmw.cmpxchg 0 acqrel
- i64.atomic.rmw.cmpxchg 0 acqrel
-
- # CHECK: i32.atomic.load8_u 0 seqcst # encoding: [0xfe,0x12,0x00,0x00]
- # DISASM: i32.atomic.load8_u 0 seqcst
- i32.atomic.load8_u 0:p2align=0 seqcst
-
- # CHECK: i64.atomic.rmw32.xchg_u 0 acqrel # encoding: [0xfe,0x47,0x22,0x11,0x00]
- # DISASM: i64.atomic.rmw32.xchg_u 0 acqrel
- i64.atomic.rmw32.xchg_u 0 acqrel
+
+ # CHECK: i32.atomic.load 0 # encoding: [0xfe,0x10,0x02,0x00]
+ # DISASM: i32.atomic.load 0
+ i32.atomic.load seqcst 0
+
+ # CHECK: i32.atomic.load acqrel 0 # encoding: [0xfe,0x10,0x22,0x01,0x00]
+ # DISASM: i32.atomic.load acqrel 0
+ i32.atomic.load acqrel 0
+
+ # CHECK: i64.atomic.load acqrel 0 # encoding: [0xfe,0x11,0x23,0x01,0x00]
+ # DISASM: i64.atomic.load acqrel 0
+ i64.atomic.load acqrel 0
+
+ # CHECK: i32.atomic.store acqrel 0 # encoding: [0xfe,0x17,0x22,0x01,0x00]
+ # DISASM: i32.atomic.store acqrel 0
+ i32.atomic.store acqrel 0
+
+ # CHECK: i64.atomic.store acqrel 8 # encoding: [0xfe,0x18,0x23,0x01,0x08]
+ # DISASM: i64.atomic.store acqrel 8
+ i64.atomic.store acqrel 8
+
+ # CHECK: i32.atomic.rmw.add acqrel 0 # encoding: [0xfe,0x1e,0x22,0x11,0x00]
+ # DISASM: i32.atomic.rmw.add acqrel 0
+ i32.atomic.rmw.add acqrel 0
+
+ # CHECK: i64.atomic.rmw.cmpxchg acqrel 0 # encoding: [0xfe,0x49,0x23,0x11,0x00]
+ # DISASM: i64.atomic.rmw.cmpxchg acqrel 0
+ i64.atomic.rmw.cmpxchg acqrel 0
+
+ # CHECK: i32.atomic.load8_u 0 # encoding: [0xfe,0x12,0x00,0x00]
+ # DISASM: i32.atomic.load8_u 0
+ i32.atomic.load8_u seqcst 0:p2align=0
+
+ # CHECK: i64.atomic.rmw32.xchg_u acqrel 0 # encoding: [0xfe,0x47,0x22,0x11,0x00]
+ # DISASM: i64.atomic.rmw32.xchg_u acqrel 0
+ i64.atomic.rmw32.xchg_u acqrel 0
end_function
>From f170409e640f3d61bbc0e59a4c01588d7003150a Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 26 Feb 2026 01:19:39 +0000
Subject: [PATCH 11/22] [WebAssembly] Reorder Order before P2Align in MCInst
and fix disassembler
This change moves the memory ordering operand before the p2align operand
in the internal MCInst representation for atomic instructions. This
provides a more consistent structure that aligns with the assembly syntax
'mnemonic order offset'.
Key changes:
- TableGen: Swapped Order and P2Align in 'ins' lists.
- Disassembler: Implemented placeholder logic to handle MEMORDER before
P2ALIGN, as the latter contains the bit indicating if an ordering follows.
- MCCodeEmitter: Updated to handle the new operand order, ensuring
MEMORDER is correctly skipped in the main loop and handled by encodeMemArg.
- AsmParser: Updated p2align fixup logic to dynamically find the operand index.
- Verification: All 415 WebAssembly tests pass, including CodeGen and MC tests.
---
.../AsmParser/WebAssemblyAsmParser.cpp | 16 ++++--
.../Disassembler/WebAssemblyDisassembler.cpp | 26 +++++++--
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 10 +++-
.../WebAssembly/WebAssemblyInstrAtomics.td | 56 +++++++++----------
4 files changed, 68 insertions(+), 40 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 3dc516cbe414e..60119d81beec5 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -1200,11 +1200,17 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
case Match_Success: {
ensureLocals(Out);
// Fix unknown p2align operands.
- auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode());
- if (Align != -1U) {
- auto &Op0 = Inst.getOperand(0);
- if (Op0.isImm() && Op0.getImm() == -1)
- Op0.setImm(Align);
+ const MCInstrDesc &Desc = MII.get(Inst.getOpcode());
+ for (unsigned i = 0; i < Inst.getNumOperands(); ++i) {
+ if (i < Desc.getNumOperands() &&
+ Desc.operands()[i].OperandType == WebAssembly::OPERAND_P2ALIGN) {
+ auto &Op = Inst.getOperand(i);
+ if (Op.isImm() && Op.getImm() == -1) {
+ auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode());
+ if (Align != -1U)
+ Op.setImm(Align);
+ }
+ }
}
if (Is64) {
// Upgrade 32-bit loads/stores to 64-bit. These mostly differ by having
diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index d71ba5978a903..f11781e42d9b1 100644
--- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -213,11 +213,25 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
return MCDisassembler::Fail;
if (OT == WebAssembly::OPERAND_P2ALIGN) {
int64_t Val = MI.getOperand(MI.getNumOperands() - 1).getImm();
- if (Val & 0x20) {
- MI.getOperand(MI.getNumOperands() - 1).setImm(Val & ~0x20);
+ if (Val & wasm::WASM_MEMARG_HAS_MEM_ORDER) {
+ MI.getOperand(MI.getNumOperands() - 1).setImm(Val & ~wasm::WASM_MEMARG_HAS_MEM_ORDER);
if (Size >= Bytes.size())
return MCDisassembler::Fail;
DecodedOrder = Bytes[Size++];
+
+ // If we already added a MEMORDER placeholder, update it.
+ for (unsigned J = 0; J < MI.getNumOperands(); J++) {
+ auto JOT = OperandTable[WasmInst->OperandStart + J];
+ if (JOT == WebAssembly::OPERAND_MEMORDER) {
+ uint8_t Order = DecodedOrder;
+ if (Order == wasm::WASM_MEM_ORDER_RMW_ACQ_REL ||
+ Order == wasm::WASM_MEM_ORDER_ACQ_REL)
+ MI.getOperand(J).setImm(wasm::WASM_MEM_ORDER_ACQ_REL);
+ else
+ MI.getOperand(J).setImm(wasm::WASM_MEM_ORDER_SEQ_CST);
+ break;
+ }
+ }
}
}
break;
@@ -277,7 +291,7 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
Val = DecodedOrder;
} else {
bool HasP2Align = false;
- for (uint8_t J = 0; J < OPI; J++)
+ for (uint8_t J = 0; J < WasmInst->NumOperands; J++)
if (OperandTable[WasmInst->OperandStart + J] ==
WebAssembly::OPERAND_P2ALIGN)
HasP2Align = true;
@@ -286,10 +300,14 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
return MCDisassembler::Fail;
Val = Bytes[Size++];
} else {
+ // If we have P2ALIGN, it will be encoded as part of the memarg,
+ // which might not have been parsed yet. Default to SEQ_CST
+ // and we will update it when we parse P2ALIGN if necessary.
Val = wasm::WASM_MEM_ORDER_SEQ_CST;
}
}
- if (Val == wasm::WASM_MEM_ORDER_RMW_ACQ_REL || Val == wasm::WASM_MEM_ORDER_ACQ_REL)
+ if (Val == wasm::WASM_MEM_ORDER_RMW_ACQ_REL ||
+ Val == wasm::WASM_MEM_ORDER_ACQ_REL)
MI.addOperand(MCOperand::createImm(wasm::WASM_MEM_ORDER_ACQ_REL));
else
MI.addOperand(MCOperand::createImm(wasm::WASM_MEM_ORDER_SEQ_CST));
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 0f377b55adc60..161de8b6fdf1c 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -84,9 +84,9 @@ void WebAssemblyMCCodeEmitter::encodeMemArg(
unsigned P2AlignIdx = I;
std::optional<unsigned> MemOrderIdx;
- if (I + 1 < Desc.getNumOperands() &&
- Desc.operands()[I + 1].OperandType == WebAssembly::OPERAND_MEMORDER)
- MemOrderIdx = I + 1;
+ if (I > 0 &&
+ Desc.operands()[I - 1].OperandType == WebAssembly::OPERAND_MEMORDER)
+ MemOrderIdx = I - 1;
uint64_t P2Align = MI.getOperand(P2AlignIdx).getImm();
uint8_t Order = wasm::WASM_MEM_ORDER_SEQ_CST;
@@ -181,6 +181,10 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
llvm::endianness::little);
break;
case WebAssembly::OPERAND_MEMORDER: {
+ if (I + 1 < Desc.getNumOperands() &&
+ Desc.operands()[I + 1].OperandType ==
+ WebAssembly::OPERAND_P2ALIGN)
+ break;
uint8_t Val = MO.getImm();
if (STI.getFeatureBits()[WebAssembly::FeatureSharedEverything]) {
if (Val == wasm::WASM_MEM_ORDER_ACQ_REL) {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
index 1d6ebd9e62d18..e0e05e7a3a979 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
@@ -35,43 +35,43 @@ multiclass ATOMIC_NRI<dag oops, dag iops, list<dag> pattern, string asmstr = "",
let hasSideEffects = 1 in {
defm MEMORY_ATOMIC_NOTIFY_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, I32:$count),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$count),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
"memory.atomic.notify \t$dst, ${order} ${off}(${addr})${p2align}, $count",
"memory.atomic.notify \t${order} ${off}${p2align}", 0x00, false>;
defm MEMORY_ATOMIC_NOTIFY_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, I32:$count),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$count),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
"memory.atomic.notify \t$dst, ${order} ${off}(${addr})${p2align}, $count",
"memory.atomic.notify \t${order} ${off}${p2align}", 0x00, true>;
let mayLoad = 1 in {
defm MEMORY_ATOMIC_WAIT32_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, I32:$exp,
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
"memory.atomic.wait32 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
"memory.atomic.wait32 \t${order} ${off}${p2align}", 0x01, false>;
defm MEMORY_ATOMIC_WAIT32_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, I32:$exp,
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
"memory.atomic.wait32 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
"memory.atomic.wait32 \t${order} ${off}${p2align}", 0x01, true>;
defm MEMORY_ATOMIC_WAIT64_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, I64:$exp,
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, I64:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
"memory.atomic.wait64 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
"memory.atomic.wait64 \t${order} ${off}${p2align}", 0x02, false>;
defm MEMORY_ATOMIC_WAIT64_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, I64:$exp,
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, I64:$exp,
I64:$timeout),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
"memory.atomic.wait64 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
"memory.atomic.wait64 \t${order} ${off}${p2align}", 0x02, true>;
} // mayLoad = 1
@@ -121,14 +121,14 @@ defm ATOMIC_FENCE : ATOMIC_NRI<(outs), (ins MemOrder:$order), [],
multiclass WebAssemblyAtomicLoad<WebAssemblyRegClass rc, string name, int Opcode> {
let mayLoad = 1, UseNamedOperandTable = 1 in {
defm "_A32": I<(outs rc:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off),
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off),
[], !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}"),
!strconcat(name, "\t${order} ${off}${p2align}"), Opcode, false>,
Requires<[HasAtomics]>;
defm "_A64": I<(outs rc:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off),
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off),
[], !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}"),
!strconcat(name, "\t${order} ${off}${p2align}"), Opcode, true>,
Requires<[HasAtomics]>;
@@ -212,14 +212,14 @@ defm : AtomicLoadPat<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
multiclass WebAssemblyAtomicStore<WebAssemblyRegClass rc, string name, int Opcode> {
let mayStore = 1, UseNamedOperandTable = 1 in {
defm "_A32" : I<(outs),
- (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, rc:$val),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
!strconcat(name, "\t${order} ${off}(${addr})${p2align}, $val"),
!strconcat(name, "\t${order} ${off}${p2align}"), Opcode, false>,
Requires<[HasAtomics]>;
defm "_A64" : I<(outs),
- (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, rc:$val),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
!strconcat(name, "\t${order} ${off}(${addr})${p2align}, $val"),
!strconcat(name, "\t${order} ${off}${p2align}"), Opcode, true>,
Requires<[HasAtomics]>;
@@ -284,14 +284,14 @@ multiclass WebAssemblyBinRMW<WebAssemblyRegClass rc, string name,
int atomic_op> {
defm "_A32" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, rc:$val),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
!strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $val"),
!strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, rc:$val),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
!strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $val"),
!strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, true>;
}
@@ -488,16 +488,16 @@ multiclass WebAssemblyTerRMW<WebAssemblyRegClass rc, string name,
int atomic_op> {
defm "_A32" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off, I32:$addr, rc:$exp,
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$exp,
rc:$new_),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset32_op:$off), [],
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
!strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $exp, $new_"),
!strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
- (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off, I64:$addr, rc:$exp,
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$exp,
rc:$new_),
- (outs), (ins P2Align:$p2align, MemOrder:$order, offset64_op:$off), [],
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
!strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $exp, $new_"),
!strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, true>;
}
>From daeb18b61eeb0b07491063cfea51dad78598c3b6 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 27 Feb 2026 00:01:30 +0000
Subject: [PATCH 12/22] simplify encoding and decoding
---
.../Disassembler/WebAssemblyDisassembler.cpp | 65 +++++++++----------
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 20 ++----
2 files changed, 35 insertions(+), 50 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index f11781e42d9b1..da209a9d20e08 100644
--- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -164,7 +164,6 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
raw_ostream &CS) const {
CommentStream = &CS;
Size = 0;
- uint8_t DecodedOrder = 0xFF;
int Opc = nextByte(Bytes, Size);
if (Opc < 0)
return MCDisassembler::Fail;
@@ -212,26 +211,31 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
if (!parseLEBImmediate(MI, Size, Bytes, false))
return MCDisassembler::Fail;
if (OT == WebAssembly::OPERAND_P2ALIGN) {
+ // The byte that encodes P2align also encodes whether a memory index
+ // and/or ordering is present.
int64_t Val = MI.getOperand(MI.getNumOperands() - 1).getImm();
if (Val & wasm::WASM_MEMARG_HAS_MEM_ORDER) {
- MI.getOperand(MI.getNumOperands() - 1).setImm(Val & ~wasm::WASM_MEMARG_HAS_MEM_ORDER);
+ // Clear the order so we just have the alignment in this operand.
+ MI.getOperand(MI.getNumOperands() - 1)
+ .setImm(Val & ~wasm::WASM_MEMARG_HAS_MEM_ORDER);
if (Size >= Bytes.size())
return MCDisassembler::Fail;
- DecodedOrder = Bytes[Size++];
-
- // If we already added a MEMORDER placeholder, update it.
- for (unsigned J = 0; J < MI.getNumOperands(); J++) {
- auto JOT = OperandTable[WasmInst->OperandStart + J];
- if (JOT == WebAssembly::OPERAND_MEMORDER) {
- uint8_t Order = DecodedOrder;
- if (Order == wasm::WASM_MEM_ORDER_RMW_ACQ_REL ||
- Order == wasm::WASM_MEM_ORDER_ACQ_REL)
- MI.getOperand(J).setImm(wasm::WASM_MEM_ORDER_ACQ_REL);
- else
- MI.getOperand(J).setImm(wasm::WASM_MEM_ORDER_SEQ_CST);
- break;
- }
- }
+ uint8_t Order = Bytes[Size++];
+ // If we have a memory ordering, it must have been preceded by a
+ // MEMORDER operand which was added as a placeholder (because we are
+ // iterating in MI operand order which has mem order first, but this
+ // byte is encoded first).
+ assert(OPI > 0 &&
+ OperandTable[WasmInst->OperandStart + OPI - 1] ==
+ WebAssembly::OPERAND_MEMORDER &&
+ "P2ALIGN with memory order not preceded by MEMORDER");
+ if (Order == wasm::WASM_MEM_ORDER_RMW_ACQ_REL ||
+ Order == wasm::WASM_MEM_ORDER_ACQ_REL)
+ MI.getOperand(MI.getNumOperands() - 2)
+ .setImm(wasm::WASM_MEM_ORDER_ACQ_REL);
+ else
+ MI.getOperand(MI.getNumOperands() - 2)
+ .setImm(wasm::WASM_MEM_ORDER_SEQ_CST);
}
}
break;
@@ -287,24 +291,17 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
}
case WebAssembly::OPERAND_MEMORDER: {
uint8_t Val;
- if (DecodedOrder != 0xFF) {
- Val = DecodedOrder;
+ if (OPI + 1 < WasmInst->NumOperands &&
+ OperandTable[WasmInst->OperandStart + OPI + 1] ==
+ WebAssembly::OPERAND_P2ALIGN) {
+ // If we have P2ALIGN next, it will be encoded as part of the memarg,
+ // which has not been parsed yet. Default to SEQ_CST
+ // and we will update it when we parse P2ALIGN if necessary.
+ Val = wasm::WASM_MEM_ORDER_SEQ_CST;
} else {
- bool HasP2Align = false;
- for (uint8_t J = 0; J < WasmInst->NumOperands; J++)
- if (OperandTable[WasmInst->OperandStart + J] ==
- WebAssembly::OPERAND_P2ALIGN)
- HasP2Align = true;
- if (!HasP2Align) {
- if (Size >= Bytes.size())
- return MCDisassembler::Fail;
- Val = Bytes[Size++];
- } else {
- // If we have P2ALIGN, it will be encoded as part of the memarg,
- // which might not have been parsed yet. Default to SEQ_CST
- // and we will update it when we parse P2ALIGN if necessary.
- Val = wasm::WASM_MEM_ORDER_SEQ_CST;
- }
+ if (Size >= Bytes.size())
+ return MCDisassembler::Fail;
+ Val = Bytes[Size++];
}
if (Val == wasm::WASM_MEM_ORDER_RMW_ACQ_REL ||
Val == wasm::WASM_MEM_ORDER_ACQ_REL)
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 161de8b6fdf1c..bbeac6f626031 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -50,7 +50,6 @@ class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
void encodeMemArg(const MCInst &MI, unsigned I, const MCInstrDesc &Desc,
const MCSubtargetInfo &STI, raw_ostream &OS,
- SmallSet<unsigned, 4> &HandledOperands,
SmallVectorImpl<MCFixup> &Fixups, uint64_t Start) const;
uint8_t getEncodedMemOrder(uint8_t Order, unsigned Opcode) const;
@@ -79,7 +78,6 @@ uint8_t WebAssemblyMCCodeEmitter::getEncodedMemOrder(uint8_t Order,
void WebAssemblyMCCodeEmitter::encodeMemArg(
const MCInst &MI, unsigned I, const MCInstrDesc &Desc,
const MCSubtargetInfo &STI, raw_ostream &OS,
- SmallSet<unsigned, 4> &HandledOperands,
SmallVectorImpl<MCFixup> &Fixups, uint64_t Start) const {
unsigned P2AlignIdx = I;
std::optional<unsigned> MemOrderIdx;
@@ -112,10 +110,6 @@ void WebAssemblyMCCodeEmitter::encodeMemArg(
OS, getEncodedMemOrder(Order, MI.getOpcode()),
llvm::endianness::little);
}
-
- // We handled the MemOrder operand, even if we didn't encode it explicitly
- if (MemOrderIdx)
- HandledOperands.insert(*MemOrderIdx);
}
void WebAssemblyMCCodeEmitter::encodeInstruction(
@@ -149,10 +143,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
encodeULEB128(MI.getNumOperands() - 2, OS);
const MCInstrDesc &Desc = MCII.get(Opcode);
- SmallSet<unsigned, 4> HandledOperands;
for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
- if (HandledOperands.count(I))
- continue;
const MCOperand &MO = MI.getOperand(I);
if (MO.isReg()) {
/* nothing to encode */
@@ -167,7 +158,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
encodeSLEB128(int32_t(MO.getImm()), OS);
break;
case WebAssembly::OPERAND_P2ALIGN:
- encodeMemArg(MI, I, Desc, STI, OS, HandledOperands, Fixups, Start);
+ encodeMemArg(MI, I, Desc, STI, OS, Fixups, Start);
break;
case WebAssembly::OPERAND_OFFSET32:
encodeULEB128(uint32_t(MO.getImm()), OS);
@@ -181,17 +172,14 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
llvm::endianness::little);
break;
case WebAssembly::OPERAND_MEMORDER: {
+ // If there is a p2align operand (everything but fence) it is encoded
+ // together with the mem ordering (in the next iteration).
if (I + 1 < Desc.getNumOperands() &&
Desc.operands()[I + 1].OperandType ==
WebAssembly::OPERAND_P2ALIGN)
break;
- uint8_t Val = MO.getImm();
+ uint8_t Val = getEncodedMemOrder(MO.getImm(), Opcode);
if (STI.getFeatureBits()[WebAssembly::FeatureSharedEverything]) {
- if (Val == wasm::WASM_MEM_ORDER_ACQ_REL) {
- StringRef Name = MCII.getName(Opcode);
- if (Name.contains("RMW") || Name.contains("CMPXCHG"))
- Val = wasm::WASM_MEM_ORDER_RMW_ACQ_REL;
- }
support::endian::write<uint8_t>(OS, Val,
llvm::endianness::little);
} else if (Opcode == WebAssembly::ATOMIC_FENCE ||
>From 0fce3849bfd19842f0cfc5c3a7826ad3f26b7d0d Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 27 Feb 2026 00:08:29 +0000
Subject: [PATCH 13/22] simplify asm parsing
---
.../AsmParser/WebAssemblyAsmParser.cpp | 46 +++++++++----------
1 file changed, 21 insertions(+), 25 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 60119d81beec5..4fd656fdd63d9 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -472,22 +472,26 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return false;
}
- bool parseMemOrderMaybe(OperandVector &Operands) {
+ bool addMemOrderOrDefault(OperandVector &Operands) {
auto &Tok = Lexer.getTok();
- if (Tok.isNot(AsmToken::Identifier))
- return true;
- StringRef S = Tok.getString();
- int64_t Order = StringSwitch<int64_t>(S)
- .Case("acqrel", wasm::WASM_MEM_ORDER_ACQ_REL)
- .Case("seqcst", wasm::WASM_MEM_ORDER_SEQ_CST)
- .Default(-1);
- if (Order == -1)
- return true;
- if (!STI->checkFeatures("+shared-everything"))
- return error("memory ordering requires shared-everything feature: ", Tok);
+ int64_t Order = wasm::WASM_MEM_ORDER_SEQ_CST;
+ if (Tok.is(AsmToken::Identifier)) {
+ StringRef S = Tok.getString();
+ Order = StringSwitch<int64_t>(S)
+ .Case("acqrel", wasm::WASM_MEM_ORDER_ACQ_REL)
+ .Case("seqcst", wasm::WASM_MEM_ORDER_SEQ_CST)
+ .Default(-1);
+ if (Order != -1) {
+ if (!STI->checkFeatures("+shared-everything"))
+ return error("memory ordering requires shared-everything feature: ",
+ Tok);
+ Parser.Lex();
+ } else {
+ Order = wasm::WASM_MEM_ORDER_SEQ_CST;
+ }
+ }
Operands.push_back(std::make_unique<WebAssemblyOperand>(
Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{Order}));
- Parser.Lex();
return false;
}
@@ -667,12 +671,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
if (pop(Name, Try))
return true;
} else if (Name == "atomic.fence") {
- if(parseMemOrderMaybe(Operands)) {
- auto Tok = Lexer.getTok();
- Operands.push_back(std::make_unique<WebAssemblyOperand>(
- Tok.getLoc(), Tok.getEndLoc(),
- WebAssemblyOperand::IntOp{wasm::WASM_MEM_ORDER_SEQ_CST}));
- }
+ if (addMemOrderOrDefault(Operands))
+ return true;
} else if (Name == "end_loop") {
if (pop(Name, Loop))
return true;
@@ -699,12 +699,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
bool IsAtomic = Name.contains("atomic.");
if (IsAtomic && Name != "atomic.fence") {
- if(parseMemOrderMaybe(Operands)) {
- auto Tok = Lexer.getTok();
- Operands.push_back(std::make_unique<WebAssemblyOperand>(
- Tok.getLoc(), Tok.getEndLoc(),
- WebAssemblyOperand::IntOp{wasm::WASM_MEM_ORDER_SEQ_CST}));
- }
+ if (addMemOrderOrDefault(Operands))
+ return true;
}
// Returns true if the next tokens are a catch clause
>From fb90dcb10f49f75b9059d4ac74fb70fda081a1bc Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 27 Feb 2026 00:40:56 +0000
Subject: [PATCH 14/22] simplify parser
---
.../AsmParser/WebAssemblyAsmParser.cpp | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 4fd656fdd63d9..ca4ab2b921d70 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -1197,16 +1197,20 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
ensureLocals(Out);
// Fix unknown p2align operands.
const MCInstrDesc &Desc = MII.get(Inst.getOpcode());
- for (unsigned i = 0; i < Inst.getNumOperands(); ++i) {
- if (i < Desc.getNumOperands() &&
- Desc.operands()[i].OperandType == WebAssembly::OPERAND_P2ALIGN) {
- auto &Op = Inst.getOperand(i);
- if (Op.isImm() && Op.getImm() == -1) {
- auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode());
- if (Align != -1U)
+ auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode());
+ if (Align != -1U) {
+ unsigned I = 0;
+ // It's operand 0 for regular memory ops and 1 for atomics.
+ for (unsigned E = Desc.getNumOperands(); I < E; ++I) {
+ if (Desc.operands()[I].OperandType == WebAssembly::OPERAND_P2ALIGN) {
+ auto &Op = Inst.getOperand(I);
+ if (Op.getImm() == -1) {
Op.setImm(Align);
+ }
+ break;
}
}
+ assert(I < 2 && "Default p2align set but operand not found");
}
if (Is64) {
// Upgrade 32-bit loads/stores to 64-bit. These mostly differ by having
>From ea2086059f75face3e18ec3baac2dc4620e72b92 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 27 Feb 2026 01:01:10 +0000
Subject: [PATCH 15/22] Simplify tablegen
---
.../WebAssembly/WebAssemblyInstrAtomics.td | 56 ++++++++-----------
1 file changed, 22 insertions(+), 34 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
index e0e05e7a3a979..ad85caac102dc 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
@@ -118,27 +118,21 @@ defm ATOMIC_FENCE : ATOMIC_NRI<(outs), (ins MemOrder:$order), [],
// Atomic loads
//===----------------------------------------------------------------------===//
-multiclass WebAssemblyAtomicLoad<WebAssemblyRegClass rc, string name, int Opcode> {
+multiclass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> {
let mayLoad = 1, UseNamedOperandTable = 1 in {
- defm "_A32": I<(outs rc:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off),
- [], !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}"),
- !strconcat(name, "\t${order} ${off}${p2align}"), Opcode, false>,
- Requires<[HasAtomics]>;
- defm "_A64": I<(outs rc:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off),
- [], !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}"),
- !strconcat(name, "\t${order} ${off}${p2align}"), Opcode, true>,
- Requires<[HasAtomics]>;
+ defm "_A32": ATOMIC_I<(outs rc:$dst),
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off),
+ [], !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, false>;
+ defm "_A64": ATOMIC_I<(outs rc:$dst),
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off),
+ [], !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, true>;
}
}
-multiclass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> {
- defm "" : WebAssemblyAtomicLoad<rc, name, !or(0xfe00, !and(0xff, atomic_op))>;
-}
-
multiclass AtomicLoadPat<ValueType ty, SDPatternOperator kind, string Name> {
def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr))),
(!cast<NI>(Name # "_A32") 0, 0, offset32_op:$offset, I32:$addr)>,
@@ -209,27 +203,21 @@ defm : AtomicLoadPat<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
// Atomic stores
//===----------------------------------------------------------------------===//
-multiclass WebAssemblyAtomicStore<WebAssemblyRegClass rc, string name, int Opcode> {
+multiclass AtomicStore<WebAssemblyRegClass rc, string name, int atomic_op> {
let mayStore = 1, UseNamedOperandTable = 1 in {
- defm "_A32" : I<(outs),
- (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
- !strconcat(name, "\t${order} ${off}(${addr})${p2align}, $val"),
- !strconcat(name, "\t${order} ${off}${p2align}"), Opcode, false>,
- Requires<[HasAtomics]>;
- defm "_A64" : I<(outs),
- (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
- !strconcat(name, "\t${order} ${off}(${addr})${p2align}, $val"),
- !strconcat(name, "\t${order} ${off}${p2align}"), Opcode, true>,
- Requires<[HasAtomics]>;
+ defm "_A32" : ATOMIC_I<(outs),
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
+ !strconcat(name, "\t${order} ${off}(${addr})${p2align}, $val"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, false>;
+ defm "_A64" : ATOMIC_I<(outs),
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
+ !strconcat(name, "\t${order} ${off}(${addr})${p2align}, $val"),
+ !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, true>;
}
}
-multiclass AtomicStore<WebAssemblyRegClass rc, string name, int atomic_op> {
- defm "" : WebAssemblyAtomicStore<rc, name, !or(0xfe00, !and(0xff, atomic_op))>;
-}
-
defm ATOMIC_STORE_I32 : AtomicStore<I32, "i32.atomic.store", 0x17>;
defm ATOMIC_STORE_I64 : AtomicStore<I64, "i64.atomic.store", 0x18>;
>From f82ed2fb42419b14ab3cfb80710c3a34aff504b4 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 27 Feb 2026 01:24:08 +0000
Subject: [PATCH 16/22] clang-format
---
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index bbeac6f626031..73fbc335f8cb0 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -75,10 +75,12 @@ uint8_t WebAssemblyMCCodeEmitter::getEncodedMemOrder(uint8_t Order,
return Order;
}
-void WebAssemblyMCCodeEmitter::encodeMemArg(
- const MCInst &MI, unsigned I, const MCInstrDesc &Desc,
- const MCSubtargetInfo &STI, raw_ostream &OS,
- SmallVectorImpl<MCFixup> &Fixups, uint64_t Start) const {
+void WebAssemblyMCCodeEmitter::encodeMemArg(const MCInst &MI, unsigned I,
+ const MCInstrDesc &Desc,
+ const MCSubtargetInfo &STI,
+ raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ uint64_t Start) const {
unsigned P2AlignIdx = I;
std::optional<unsigned> MemOrderIdx;
@@ -106,9 +108,9 @@ void WebAssemblyMCCodeEmitter::encodeMemArg(
// Memory index will go here once we support multi-memory.
if (P2Align & wasm::WASM_MEMARG_HAS_MEM_ORDER) {
- support::endian::write<uint8_t>(
- OS, getEncodedMemOrder(Order, MI.getOpcode()),
- llvm::endianness::little);
+ support::endian::write<uint8_t>(OS,
+ getEncodedMemOrder(Order, MI.getOpcode()),
+ llvm::endianness::little);
}
}
@@ -180,12 +182,10 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
break;
uint8_t Val = getEncodedMemOrder(MO.getImm(), Opcode);
if (STI.getFeatureBits()[WebAssembly::FeatureSharedEverything]) {
- support::endian::write<uint8_t>(OS, Val,
- llvm::endianness::little);
+ support::endian::write<uint8_t>(OS, Val, llvm::endianness::little);
} else if (Opcode == WebAssembly::ATOMIC_FENCE ||
Opcode == WebAssembly::ATOMIC_FENCE_S) {
- support::endian::write<uint8_t>(OS, 0,
- llvm::endianness::little);
+ support::endian::write<uint8_t>(OS, 0, llvm::endianness::little);
}
break;
}
>From 01383e517dd2ff3269130ffb4a0c399ca3e35422 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 27 Feb 2026 17:19:08 +0000
Subject: [PATCH 17/22] put back removed comment
---
llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index ca4ab2b921d70..02c73bec9b3ba 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -520,6 +520,9 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
if (IsLoadStoreLane && Operands.size() == 4)
return false;
// Alignment not specified (or atomics, must use default alignment).
+ // We can't just call WebAssembly::GetDefaultP2Align since we don't have
+ // an opcode until after the assembly matcher, so set a default to fix
+ // up later.
auto Tok = Lexer.getTok();
Operands.push_back(std::make_unique<WebAssemblyOperand>(
Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
>From 8c5aae45e4a36e646b2e65b2350d5ff686dc34e6 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Mon, 2 Mar 2026 21:54:38 +0000
Subject: [PATCH 18/22] 80 col td file
---
.../WebAssembly/WebAssemblyInstrAtomics.td | 134 +++++++++++-------
.../WebAssembly/WebAssemblyInstrInfo.td | 10 +-
.../Target/WebAssembly/WebAssemblySubtarget.h | 4 +-
.../test/CodeGen/WebAssembly/atomic-fence.mir | 4 +-
4 files changed, 89 insertions(+), 63 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
index ad85caac102dc..c10c8805f8c54 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
@@ -35,44 +35,52 @@ multiclass ATOMIC_NRI<dag oops, dag iops, list<dag> pattern, string asmstr = "",
let hasSideEffects = 1 in {
defm MEMORY_ATOMIC_NOTIFY_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$count),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
- "memory.atomic.notify \t$dst, ${order} ${off}(${addr})${p2align}, $count",
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr,
+ I32:$count),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off),
+ [], "memory.atomic.notify \t$dst, "
+ "${order} ${off}(${addr})${p2align}, $count",
"memory.atomic.notify \t${order} ${off}${p2align}", 0x00, false>;
defm MEMORY_ATOMIC_NOTIFY_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$count),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
- "memory.atomic.notify \t$dst, ${order} ${off}(${addr})${p2align}, $count",
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr,
+ I32:$count),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off),
+ [], "memory.atomic.notify \t$dst, "
+ "${order} ${off}(${addr})${p2align}, $count",
"memory.atomic.notify \t${order} ${off}${p2align}", 0x00, true>;
let mayLoad = 1 in {
defm MEMORY_ATOMIC_WAIT32_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$exp,
- I64:$timeout),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
- "memory.atomic.wait32 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr,
+ I32:$exp, I64:$timeout),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off),
+ [], "memory.atomic.wait32 \t$dst, "
+ "${order} ${off}(${addr})${p2align}, $exp, $timeout",
"memory.atomic.wait32 \t${order} ${off}${p2align}", 0x01, false>;
defm MEMORY_ATOMIC_WAIT32_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$exp,
- I64:$timeout),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
- "memory.atomic.wait32 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr,
+ I32:$exp, I64:$timeout),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off),
+ [], "memory.atomic.wait32 \t$dst, "
+ "${order} ${off}(${addr})${p2align}, $exp, $timeout",
"memory.atomic.wait32 \t${order} ${off}${p2align}", 0x01, true>;
defm MEMORY_ATOMIC_WAIT64_A32 :
ATOMIC_I<(outs I32:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, I64:$exp,
- I64:$timeout),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
- "memory.atomic.wait64 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr,
+ I64:$exp, I64:$timeout),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off),
+ [], "memory.atomic.wait64 \t$dst, "
+ "${order} ${off}(${addr})${p2align}, $exp, $timeout",
"memory.atomic.wait64 \t${order} ${off}${p2align}", 0x02, false>;
defm MEMORY_ATOMIC_WAIT64_A64 :
ATOMIC_I<(outs I32:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, I64:$exp,
- I64:$timeout),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
- "memory.atomic.wait64 \t$dst, ${order} ${off}(${addr})${p2align}, $exp, $timeout",
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr,
+ I64:$exp, I64:$timeout),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off),
+ [], "memory.atomic.wait64 \t$dst, "
+ "${order} ${off}(${addr})${p2align}, $exp, $timeout",
"memory.atomic.wait64 \t${order} ${off}${p2align}", 0x02, true>;
} // mayLoad = 1
} // hasSideEffects = 1
@@ -121,15 +129,23 @@ defm ATOMIC_FENCE : ATOMIC_NRI<(outs), (ins MemOrder:$order), [],
multiclass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> {
let mayLoad = 1, UseNamedOperandTable = 1 in {
defm "_A32": ATOMIC_I<(outs rc:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off),
- [], !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}"),
- !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, false>;
+ (ins MemOrder:$order, P2Align:$p2align,
+ offset32_op:$off, I32:$addr),
+ (outs), (ins MemOrder:$order, P2Align:$p2align,
+ offset32_op:$off),
+ [], !strconcat(name, "\t$dst, ${order} "
+ "${off}(${addr})${p2align}"),
+ !strconcat(name, "\t${order} ${off}${p2align}"),
+ atomic_op, false>;
defm "_A64": ATOMIC_I<(outs rc:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off),
- [], !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}"),
- !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, true>;
+ (ins MemOrder:$order, P2Align:$p2align,
+ offset64_op:$off, I64:$addr),
+ (outs), (ins MemOrder:$order, P2Align:$p2align,
+ offset64_op:$off),
+ [], !strconcat(name, "\t$dst, ${order} "
+ "${off}(${addr})${p2align}"),
+ !strconcat(name, "\t${order} ${off}${p2align}"),
+ atomic_op, true>;
}
}
@@ -206,15 +222,23 @@ defm : AtomicLoadPat<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
multiclass AtomicStore<WebAssemblyRegClass rc, string name, int atomic_op> {
let mayStore = 1, UseNamedOperandTable = 1 in {
defm "_A32" : ATOMIC_I<(outs),
- (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
- !strconcat(name, "\t${order} ${off}(${addr})${p2align}, $val"),
- !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, false>;
+ (ins MemOrder:$order, P2Align:$p2align,
+ offset32_op:$off, I32:$addr, rc:$val),
+ (outs), (ins MemOrder:$order, P2Align:$p2align,
+ offset32_op:$off), [],
+ !strconcat(name, "\t${order} ${off}"
+ "(${addr})${p2align}, $val"),
+ !strconcat(name, "\t${order} ${off}${p2align}"),
+ atomic_op, false>;
defm "_A64" : ATOMIC_I<(outs),
- (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
- !strconcat(name, "\t${order} ${off}(${addr})${p2align}, $val"),
- !strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, true>;
+ (ins MemOrder:$order, P2Align:$p2align,
+ offset64_op:$off, I64:$addr, rc:$val),
+ (outs), (ins MemOrder:$order, P2Align:$p2align,
+ offset64_op:$off), [],
+ !strconcat(name, "\t${order} ${off}"
+ "(${addr})${p2align}, $val"),
+ !strconcat(name, "\t${order} ${off}${p2align}"),
+ atomic_op, true>;
}
}
@@ -272,15 +296,19 @@ multiclass WebAssemblyBinRMW<WebAssemblyRegClass rc, string name,
int atomic_op> {
defm "_A32" :
ATOMIC_I<(outs rc:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
- !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $val"),
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off,
+ I32:$addr, rc:$val),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off),
+ [], !strconcat(name, "\t$dst, ${order} "
+ "${off}(${addr})${p2align}, $val"),
!strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
- !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $val"),
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off,
+ I64:$addr, rc:$val),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off),
+ [], !strconcat(name, "\t$dst, ${order} "
+ "${off}(${addr})${p2align}, $val"),
!strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, true>;
}
@@ -476,17 +504,19 @@ multiclass WebAssemblyTerRMW<WebAssemblyRegClass rc, string name,
int atomic_op> {
defm "_A32" :
ATOMIC_I<(outs rc:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$exp,
- rc:$new_),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off), [],
- !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $exp, $new_"),
+ (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off,
+ I32:$addr, rc:$exp, rc:$new_),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset32_op:$off),
+ [], !strconcat(name, "\t$dst, ${order} "
+ "${off}(${addr})${p2align}, $exp, $new_"),
!strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, false>;
defm "_A64" :
ATOMIC_I<(outs rc:$dst),
- (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$exp,
- rc:$new_),
- (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off), [],
- !strconcat(name, "\t$dst, ${order} ${off}(${addr})${p2align}, $exp, $new_"),
+ (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off,
+ I64:$addr, rc:$exp, rc:$new_),
+ (outs), (ins MemOrder:$order, P2Align:$p2align, offset64_op:$off),
+ [], !strconcat(name, "\t$dst, ${order} "
+ "${off}(${addr})${p2align}, $exp, $new_"),
!strconcat(name, "\t${order} ${off}${p2align}"), atomic_op, true>;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index d0f21491ae0a6..cf733ac1e66b6 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -83,17 +83,13 @@ def HasRelaxedSIMD :
Predicate<"Subtarget->hasRelaxedSIMD()">,
AssemblerPredicate<(all_of FeatureRelaxedSIMD), "relaxed-simd">;
-def HasSignExt :
- Predicate<"Subtarget->hasSignExt()">,
- AssemblerPredicate<(all_of FeatureSignExt), "sign-ext">;
-
def HasSharedEverything :
Predicate<"Subtarget->hasSharedEverything()">,
AssemblerPredicate<(all_of FeatureSharedEverything), "shared-everything">;
-def NotHasSharedEverything :
- Predicate<"!Subtarget->hasSharedEverything()">,
- AssemblerPredicate<(all_of (not FeatureSharedEverything)), "shared-everything">;
+def HasSignExt :
+ Predicate<"Subtarget->hasSignExt()">,
+ AssemblerPredicate<(all_of FeatureSignExt), "sign-ext">;
def HasSIMD128 :
Predicate<"Subtarget->hasSIMD128()">,
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
index 03ec7685c679d..41d9cb350db51 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
@@ -115,14 +115,14 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
bool hasExceptionHandling() const { return HasExceptionHandling; }
bool hasExtendedConst() const { return HasExtendedConst; }
bool hasFP16() const { return HasFP16; }
+ bool hasGC() const { return HasGC; }
bool hasMultiMemory() const { return HasMultiMemory; }
bool hasMultivalue() const { return HasMultivalue; }
bool hasMutableGlobals() const { return HasMutableGlobals; }
bool hasNontrappingFPToInt() const { return HasNontrappingFPToInt; }
bool hasReferenceTypes() const { return HasReferenceTypes; }
- bool hasSharedEverything() const { return HasSharedEverything; }
- bool hasGC() const { return HasGC; }
bool hasRelaxedSIMD() const { return SIMDLevel >= RelaxedSIMD; }
+ bool hasSharedEverything() const { return HasSharedEverything; }
bool hasSignExt() const { return HasSignExt; }
bool hasSIMD128() const { return SIMDLevel >= SIMD128; }
bool hasTailCall() const { return HasTailCall; }
diff --git a/llvm/test/CodeGen/WebAssembly/atomic-fence.mir b/llvm/test/CodeGen/WebAssembly/atomic-fence.mir
index 4e8a32f09da77..bb8854b602bb7 100644
--- a/llvm/test/CodeGen/WebAssembly/atomic-fence.mir
+++ b/llvm/test/CodeGen/WebAssembly/atomic-fence.mir
@@ -34,7 +34,7 @@ body: |
liveins: $arguments
%0:i32 = CONST_I32 0, implicit-def $arguments
- %1:i32 = MEMORY_ATOMIC_NOTIFY_A32 2, 0, 0, %0:i32, %0:i32, implicit-def $arguments
+ %1:i32 = MEMORY_ATOMIC_NOTIFY_A32 0, 2, 0, %0:i32, %0:i32, implicit-def $arguments
COMPILER_FENCE implicit-def $arguments
%2:i32 = ADD_I32 %0:i32, %0:i32, implicit-def $arguments
CALL @foo, %2:i32, %1:i32, implicit-def $arguments
@@ -58,7 +58,7 @@ body: |
liveins: $arguments
%0:i32 = CONST_I32 0, implicit-def $arguments
- %1:i32 = MEMORY_ATOMIC_NOTIFY_A32 2, 0, 0, %0:i32, %0:i32, implicit-def $arguments
+ %1:i32 = MEMORY_ATOMIC_NOTIFY_A32 0, 2, 0, %0:i32, %0:i32, implicit-def $arguments
ATOMIC_FENCE 0, implicit-def $arguments
%2:i32 = ADD_I32 %0:i32, %0:i32, implicit-def $arguments
CALL @foo, %2:i32, %1:i32, implicit-def $arguments
>From fe50966f8a970c5f3a5c164dd95e7c404f52d24c Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Tue, 3 Mar 2026 17:41:46 +0000
Subject: [PATCH 19/22] review comments
---
.../AsmParser/WebAssemblyAsmParser.cpp | 4 +-
.../Disassembler/WebAssemblyDisassembler.cpp | 3 +-
.../MCTargetDesc/WebAssemblyInstPrinter.cpp | 6 +--
.../MCTargetDesc/WebAssemblyInstPrinter.h | 2 -
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 42 ++++++++-----------
.../MCTargetDesc/WebAssemblyMCTargetDesc.h | 2 +-
llvm/lib/Target/WebAssembly/WebAssembly.td | 8 ++--
.../WebAssembly/WebAssemblyInstrInfo.td | 8 ++--
.../Target/WebAssembly/WebAssemblySubtarget.h | 4 +-
llvm/test/MC/WebAssembly/atomics-encodings.s | 2 +-
.../MC/WebAssembly/atomics-orderings-errors.s | 6 +--
llvm/test/MC/WebAssembly/atomics-orderings.s | 12 +++---
12 files changed, 43 insertions(+), 56 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 02c73bec9b3ba..91e36a7d4eed8 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -482,8 +482,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
.Case("seqcst", wasm::WASM_MEM_ORDER_SEQ_CST)
.Default(-1);
if (Order != -1) {
- if (!STI->checkFeatures("+shared-everything"))
- return error("memory ordering requires shared-everything feature: ",
+ if (!STI->checkFeatures("+relaxed-atomics"))
+ return error("memory ordering requires relaxed-atomics feature: ",
Tok);
Parser.Lex();
} else {
diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index da209a9d20e08..15b2dbb81bdbd 100644
--- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -283,7 +283,7 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
return MCDisassembler::Fail;
break;
}
- // Vector lane operands and memory ordering (not LEB encoded).
+ // Vector lane operands (not LEB encoded).
case WebAssembly::OPERAND_VEC_I8IMM: {
if (!parseImmediate<uint8_t>(MI, Size, Bytes))
return MCDisassembler::Fail;
@@ -299,6 +299,7 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
// and we will update it when we parse P2ALIGN if necessary.
Val = wasm::WASM_MEM_ORDER_SEQ_CST;
} else {
+ // atomic.fence instructions have no p2align operand.
if (Size >= Bytes.size())
return MCDisassembler::Fail;
Val = Bytes[Size++];
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 3ce881b119682..1bde070ef4f10 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -48,7 +48,6 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
StringRef Annot,
const MCSubtargetInfo &STI,
raw_ostream &OS) {
- this->STI = &STI;
switch (MI->getOpcode()) {
case WebAssembly::CALL_INDIRECT_S:
case WebAssembly::RET_CALL_INDIRECT_S: {
@@ -375,11 +374,8 @@ void WebAssemblyInstPrinter::printWebAssemblyMemOrderOperand(const MCInst *MI,
unsigned OpNo,
raw_ostream &O) {
int64_t Imm = MI->getOperand(OpNo).getImm();
- unsigned Opcode = MI->getOpcode();
- bool IsFence = Opcode == WebAssembly::ATOMIC_FENCE ||
- Opcode == WebAssembly::ATOMIC_FENCE_S;
- if (Imm == wasm::WASM_MEM_ORDER_SEQ_CST && !IsFence)
+ if (Imm == wasm::WASM_MEM_ORDER_SEQ_CST)
return;
switch (Imm) {
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
index 0caeb5a53b8e3..7181641c81b3c 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
@@ -31,8 +31,6 @@ class WebAssemblyInstPrinter final : public MCInstPrinter {
enum EHInstKind { TRY, CATCH_LEGACY, CATCH_ALL_LEGACY };
SmallVector<EHInstKind, 4> EHInstStack;
- const MCSubtargetInfo *STI = nullptr;
-
public:
WebAssemblyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
const MCRegisterInfo &MRI);
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 73fbc335f8cb0..7af89f7da015c 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -13,7 +13,6 @@
#include "MCTargetDesc/WebAssemblyFixupKinds.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
-#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
@@ -48,9 +47,10 @@ class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const override;
- void encodeMemArg(const MCInst &MI, unsigned I, const MCInstrDesc &Desc,
- const MCSubtargetInfo &STI, raw_ostream &OS,
- SmallVectorImpl<MCFixup> &Fixups, uint64_t Start) const;
+ void encodeMemArgNoOffset(const MCInst &MI, unsigned P2AlignIdx,
+ const MCInstrDesc &Desc, const MCSubtargetInfo &STI,
+ raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
+ uint64_t Start) const;
uint8_t getEncodedMemOrder(uint8_t Order, unsigned Opcode) const;
@@ -75,29 +75,21 @@ uint8_t WebAssemblyMCCodeEmitter::getEncodedMemOrder(uint8_t Order,
return Order;
}
-void WebAssemblyMCCodeEmitter::encodeMemArg(const MCInst &MI, unsigned I,
- const MCInstrDesc &Desc,
- const MCSubtargetInfo &STI,
- raw_ostream &OS,
- SmallVectorImpl<MCFixup> &Fixups,
- uint64_t Start) const {
- unsigned P2AlignIdx = I;
- std::optional<unsigned> MemOrderIdx;
-
- if (I > 0 &&
- Desc.operands()[I - 1].OperandType == WebAssembly::OPERAND_MEMORDER)
- MemOrderIdx = I - 1;
-
+void WebAssemblyMCCodeEmitter::encodeMemArgNoOffset(
+ const MCInst &MI, unsigned P2AlignIdx, const MCInstrDesc &Desc,
+ const MCSubtargetInfo &STI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups, uint64_t Start) const {
uint64_t P2Align = MI.getOperand(P2AlignIdx).getImm();
uint8_t Order = wasm::WASM_MEM_ORDER_SEQ_CST;
// Atomic instructions always have an ordering, but if it's SEQ_CST then we
- // don't use the shared-everything encoding (even if shared everything is
+ // don't use the relaxed-atomics encoding (even if relaxed-atomics is
// enabled) because the original encoding is smaller.
- if (MemOrderIdx) {
- Order = MI.getOperand(*MemOrderIdx).getImm();
+ if (P2AlignIdx > 0 &&
+ Desc.operands()[P2AlignIdx - 1].OperandType == WebAssembly::OPERAND_MEMORDER) {
+ Order = MI.getOperand(P2AlignIdx - 1).getImm();
if (Order != wasm::WASM_MEM_ORDER_SEQ_CST) {
- assert(STI.getFeatureBits()[WebAssembly::FeatureSharedEverything] &&
+ assert(STI.getFeatureBits()[WebAssembly::FeatureRelaxedAtomics] &&
"Non-default atomic ordering but feature not enabled");
P2Align |= wasm::WASM_MEMARG_HAS_MEM_ORDER;
}
@@ -160,7 +152,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
encodeSLEB128(int32_t(MO.getImm()), OS);
break;
case WebAssembly::OPERAND_P2ALIGN:
- encodeMemArg(MI, I, Desc, STI, OS, Fixups, Start);
+ encodeMemArgNoOffset(MI, I, Desc, STI, OS, Fixups, Start);
break;
case WebAssembly::OPERAND_OFFSET32:
encodeULEB128(uint32_t(MO.getImm()), OS);
@@ -181,10 +173,10 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
WebAssembly::OPERAND_P2ALIGN)
break;
uint8_t Val = getEncodedMemOrder(MO.getImm(), Opcode);
- if (STI.getFeatureBits()[WebAssembly::FeatureSharedEverything]) {
+ if (STI.getFeatureBits()[WebAssembly::FeatureRelaxedAtomics]) {
support::endian::write<uint8_t>(OS, Val, llvm::endianness::little);
- } else if (Opcode == WebAssembly::ATOMIC_FENCE ||
- Opcode == WebAssembly::ATOMIC_FENCE_S) {
+ } else {
+ assert(Opcode == WebAssembly::ATOMIC_FENCE_S);
support::endian::write<uint8_t>(OS, 0, llvm::endianness::little);
}
break;
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
index 623e7afb4a225..658e216992c01 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
@@ -82,7 +82,7 @@ enum OperandType {
OPERAND_TABLE,
/// A list of catch clauses for try_table.
OPERAND_CATCH_LIST,
- /// memory ordering immediate for atomic instructions.
+ /// Memory ordering immediate for atomic instructions.
OPERAND_MEMORDER,
};
} // end namespace WebAssembly
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td
index 53cdc120a5931..7038c1e71fae4 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.td
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.td
@@ -73,6 +73,10 @@ def FeatureReferenceTypes :
SubtargetFeature<"reference-types", "HasReferenceTypes", "true",
"Enable reference types">;
+def FeatureRelaxedAtomics :
+ SubtargetFeature<"relaxed-atomics", "HasRelaxedAtomics", "true",
+ "Enable relaxed-atomics proposal">;
+
def FeatureRelaxedSIMD :
SubtargetFeature<"relaxed-simd", "SIMDLevel", "RelaxedSIMD",
"Enable relaxed-simd instructions">;
@@ -81,10 +85,6 @@ def FeatureSignExt :
SubtargetFeature<"sign-ext", "HasSignExt", "true",
"Enable sign extension operators">;
-def FeatureSharedEverything :
- SubtargetFeature<"shared-everything", "HasSharedEverything", "true",
- "Enable shared-everything-threads proposal">;
-
def FeatureSIMD128 : SubtargetFeature<"simd128", "SIMDLevel", "SIMD128",
"Enable 128-bit SIMD">;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index cf733ac1e66b6..95b2021176b68 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -79,14 +79,14 @@ def HasReferenceTypes :
Predicate<"Subtarget->hasReferenceTypes()">,
AssemblerPredicate<(all_of FeatureReferenceTypes), "reference-types">;
+def HasRelaxedAtomics :
+ Predicate<"Subtarget->hasRelaxedAtomics()">,
+ AssemblerPredicate<(all_of FeatureRelaxedAtomics), "relaxed-atomics">;
+
def HasRelaxedSIMD :
Predicate<"Subtarget->hasRelaxedSIMD()">,
AssemblerPredicate<(all_of FeatureRelaxedSIMD), "relaxed-simd">;
-def HasSharedEverything :
- Predicate<"Subtarget->hasSharedEverything()">,
- AssemblerPredicate<(all_of FeatureSharedEverything), "shared-everything">;
-
def HasSignExt :
Predicate<"Subtarget->hasSignExt()">,
AssemblerPredicate<(all_of FeatureSignExt), "sign-ext">;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
index 41d9cb350db51..798dea25ef5e6 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
@@ -57,7 +57,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
bool HasMutableGlobals = false;
bool HasNontrappingFPToInt = false;
bool HasReferenceTypes = false;
- bool HasSharedEverything = false;
+ bool HasRelaxedAtomics = false;
bool HasSignExt = false;
bool HasTailCall = false;
bool HasWideArithmetic = false;
@@ -121,8 +121,8 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
bool hasMutableGlobals() const { return HasMutableGlobals; }
bool hasNontrappingFPToInt() const { return HasNontrappingFPToInt; }
bool hasReferenceTypes() const { return HasReferenceTypes; }
+ bool hasRelaxedAtomics() const { return HasRelaxedAtomics; }
bool hasRelaxedSIMD() const { return SIMDLevel >= RelaxedSIMD; }
- bool hasSharedEverything() const { return HasSharedEverything; }
bool hasSignExt() const { return HasSignExt; }
bool hasSIMD128() const { return SIMDLevel >= SIMD128; }
bool hasTailCall() const { return HasTailCall; }
diff --git a/llvm/test/MC/WebAssembly/atomics-encodings.s b/llvm/test/MC/WebAssembly/atomics-encodings.s
index f16b5b9dab7eb..aa0117d623e45 100644
--- a/llvm/test/MC/WebAssembly/atomics-encodings.s
+++ b/llvm/test/MC/WebAssembly/atomics-encodings.s
@@ -10,7 +10,7 @@ main:
# CHECK: memory.atomic.wait64 0 # encoding: [0xfe,0x02,0x03,0x00]
memory.atomic.wait64 0
- # CHECK: atomic.fence seqcst # encoding: [0xfe,0x03,0x00]
+ # CHECK: atomic.fence # encoding: [0xfe,0x03,0x00]
atomic.fence
# CHECK: i32.atomic.load 0 # encoding: [0xfe,0x10,0x02,0x00]
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings-errors.s b/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
index 573be35ef5724..755951e326381 100644
--- a/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
+++ b/llvm/test/MC/WebAssembly/atomics-orderings-errors.s
@@ -3,13 +3,13 @@
main:
.functype main () -> ()
- # CHECK: :[[@LINE+1]]:16: error: memory ordering requires shared-everything feature: acqrel
+ # CHECK: :[[@LINE+1]]:16: error: memory ordering requires relaxed-atomics feature: acqrel
atomic.fence acqrel
- # CHECK: :[[@LINE+1]]:19: error: memory ordering requires shared-everything feature: acqrel
+ # CHECK: :[[@LINE+1]]:19: error: memory ordering requires relaxed-atomics feature: acqrel
i32.atomic.load acqrel 0
- # CHECK: :[[@LINE+1]]:22: error: memory ordering requires shared-everything feature: seqcst
+ # CHECK: :[[@LINE+1]]:22: error: memory ordering requires relaxed-atomics feature: seqcst
i32.atomic.rmw.add seqcst 0
end_function
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings.s b/llvm/test/MC/WebAssembly/atomics-orderings.s
index 05d5057e89153..adee1a8a93a09 100644
--- a/llvm/test/MC/WebAssembly/atomics-orderings.s
+++ b/llvm/test/MC/WebAssembly/atomics-orderings.s
@@ -1,21 +1,21 @@
-# RUN: llvm-mc -no-type-check -show-encoding -triple=wasm32-unknown-unknown -mattr=+atomics,+shared-everything < %s | FileCheck %s
-# RUN: llvm-mc -no-type-check -triple=wasm32-unknown-unknown -mattr=+atomics,+shared-everything %s -filetype=obj -o - | llvm-objdump --no-print-imm-hex -d - | FileCheck %s --check-prefix=DISASM
+# RUN: llvm-mc -no-type-check -show-encoding -triple=wasm32-unknown-unknown -mattr=+atomics,+relaxed-atomics < %s | FileCheck %s
+# RUN: llvm-mc -no-type-check -triple=wasm32-unknown-unknown -mattr=+atomics,+relaxed-atomics %s -filetype=obj -o - | llvm-objdump --no-print-imm-hex -d - | FileCheck %s --check-prefix=DISASM
.section .text.main,"",@
main:
.functype main () -> ()
atomic.fence seqcst
- # CHECK: atomic.fence seqcst # encoding: [0xfe,0x03,0x00]
- # DISASM: atomic.fence seqcst
+ # CHECK: atomic.fence # encoding: [0xfe,0x03,0x00]
+ # DISASM: atomic.fence
atomic.fence acqrel
# CHECK: atomic.fence acqrel # encoding: [0xfe,0x03,0x01]
# DISASM: atomic.fence acqrel
atomic.fence
- # CHECK: atomic.fence seqcst # encoding: [0xfe,0x03,0x00]
- # DISASM: atomic.fence seqcst
+ # CHECK: atomic.fence # encoding: [0xfe,0x03,0x00]
+ # DISASM: atomic.fence
# CHECK: i32.atomic.load 0 # encoding: [0xfe,0x10,0x02,0x00]
# DISASM: i32.atomic.load 0
>From 3c38d3330712c68b1ce5ff958cf0c39f3c660110 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Tue, 3 Mar 2026 18:05:20 +0000
Subject: [PATCH 20/22] missed one comment; also clang-format
---
.../Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp | 6 +-----
.../WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 4 ++--
2 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 91e36a7d4eed8..6228796401ef2 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -673,9 +673,6 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
} else if (Name == "delegate") {
if (pop(Name, Try))
return true;
- } else if (Name == "atomic.fence") {
- if (addMemOrderOrDefault(Operands))
- return true;
} else if (Name == "end_loop") {
if (pop(Name, Loop))
return true;
@@ -700,8 +697,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
ExpectFuncType = true;
}
- bool IsAtomic = Name.contains("atomic.");
- if (IsAtomic && Name != "atomic.fence") {
+ if (Name.contains("atomic.")) {
if (addMemOrderOrDefault(Operands))
return true;
}
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 7af89f7da015c..48b3883413e93 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -85,8 +85,8 @@ void WebAssemblyMCCodeEmitter::encodeMemArgNoOffset(
// Atomic instructions always have an ordering, but if it's SEQ_CST then we
// don't use the relaxed-atomics encoding (even if relaxed-atomics is
// enabled) because the original encoding is smaller.
- if (P2AlignIdx > 0 &&
- Desc.operands()[P2AlignIdx - 1].OperandType == WebAssembly::OPERAND_MEMORDER) {
+ if (P2AlignIdx > 0 && Desc.operands()[P2AlignIdx - 1].OperandType ==
+ WebAssembly::OPERAND_MEMORDER) {
Order = MI.getOperand(P2AlignIdx - 1).getImm();
if (Order != wasm::WASM_MEM_ORDER_SEQ_CST) {
assert(STI.getFeatureBits()[WebAssembly::FeatureRelaxedAtomics] &&
>From 669b4a39263da564520111713466caa8248f2050 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Wed, 4 Mar 2026 00:45:10 +0000
Subject: [PATCH 21/22] Print 'seqcst' when feature enabled and not otherwise
---
.../MCTargetDesc/WebAssemblyInstPrinter.cpp | 35 ++++++++++---------
.../MCTargetDesc/WebAssemblyInstPrinter.h | 16 ++++++---
llvm/lib/Target/WebAssembly/WebAssembly.td | 2 +-
llvm/test/MC/WebAssembly/atomics-orderings.s | 31 ++++++++++------
4 files changed, 50 insertions(+), 34 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 1bde070ef4f10..b998194e70dbc 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -64,17 +64,17 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
const unsigned TypeOperand = 0;
const unsigned TableOperand = 1;
if (MI->getOperand(TableOperand).isExpr()) {
- printOperand(MI, TableOperand, OS);
+ printOperand(MI, TableOperand, STI, OS);
OS << ", ";
} else {
assert(MI->getOperand(TableOperand).getImm() == 0);
}
- printOperand(MI, TypeOperand, OS);
+ printOperand(MI, TypeOperand, STI, OS);
break;
}
default:
// Print the instruction (this uses the AsmStrings from the .td files).
- printInstruction(MI, Address, OS);
+ printInstruction(MI, Address, STI, OS);
break;
}
@@ -101,7 +101,7 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
}
if (NeedsComma)
OS << ", ";
- printOperand(MI, I, OS, I - Start < NumVariadicDefs);
+ printOperand(MI, I, STI, OS, I - Start < NumVariadicDefs);
NeedsComma = true;
}
}
@@ -313,6 +313,7 @@ static std::string toString(const APFloat &FP) {
}
void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O, bool IsVariadicDef) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isReg()) {
@@ -351,6 +352,7 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
}
void WebAssemblyInstPrinter::printBrList(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
O << "{";
for (unsigned I = OpNo, E = MI->getNumOperands(); I != E; ++I) {
@@ -361,39 +363,37 @@ void WebAssemblyInstPrinter::printBrList(const MCInst *MI, unsigned OpNo,
O << "}";
}
-void WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand(const MCInst *MI,
- unsigned OpNo,
- raw_ostream &O) {
+void WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand(
+ const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O) {
int64_t Imm = MI->getOperand(OpNo).getImm();
if (Imm == WebAssembly::GetDefaultP2Align(MI->getOpcode()))
return;
O << ":p2align=" << Imm;
}
-void WebAssemblyInstPrinter::printWebAssemblyMemOrderOperand(const MCInst *MI,
- unsigned OpNo,
- raw_ostream &O) {
+void WebAssemblyInstPrinter::printWebAssemblyMemOrderOperand(
+ const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O) {
int64_t Imm = MI->getOperand(OpNo).getImm();
- if (Imm == wasm::WASM_MEM_ORDER_SEQ_CST)
- return;
-
switch (Imm) {
case wasm::WASM_MEM_ORDER_RMW_ACQ_REL:
case wasm::WASM_MEM_ORDER_ACQ_REL:
O << "acqrel";
break;
case wasm::WASM_MEM_ORDER_SEQ_CST:
- O << "seqcst";
+ if (STI.getFeatureBits()[WebAssembly::FeatureRelaxedAtomics])
+ O << "seqcst";
break;
default:
llvm_unreachable("Unknown memory ordering");
}
}
-void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI,
- unsigned OpNo,
- raw_ostream &O) {
+void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(
+ const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isImm()) {
auto Imm = static_cast<unsigned>(Op.getImm());
@@ -412,6 +412,7 @@ void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI,
}
void WebAssemblyInstPrinter::printCatchList(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned OpIdx = OpNo;
const MCOperand &Op = MI->getOperand(OpIdx++);
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
index 7181641c81b3c..b8424ff4dd52b 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
@@ -40,21 +40,27 @@ class WebAssemblyInstPrinter final : public MCInstPrinter {
const MCSubtargetInfo &STI, raw_ostream &OS) override;
// Used by tblegen code.
- void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O,
- bool IsVariadicDef = false);
- void printBrList(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O, bool IsVariadicDef = false);
+ void printBrList(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
void printWebAssemblyP2AlignOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O);
void printWebAssemblyMemOrderOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O);
void printWebAssemblySignatureOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O);
- void printCatchList(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printCatchList(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
// Autogenerated by tblgen.
std::pair<const char *, uint64_t>
getMnemonic(const MCInst &MI) const override;
- void printInstruction(const MCInst *MI, uint64_t Address, raw_ostream &O);
+ void printInstruction(const MCInst *MI, uint64_t Address,
+ const MCSubtargetInfo &STI, raw_ostream &O);
static const char *getRegisterName(MCRegister Reg);
};
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td
index 7038c1e71fae4..06cf468d02eba 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.td
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.td
@@ -170,7 +170,7 @@ def WebAssemblyAsmParser : AsmParser {
def WebAssemblyAsmWriter : AsmWriter {
string AsmWriterClassName = "InstPrinter";
- int PassSubtarget = 0;
+ int PassSubtarget = 1;
int Variant = 0;
bit isMCAsmWriter = 1;
}
diff --git a/llvm/test/MC/WebAssembly/atomics-orderings.s b/llvm/test/MC/WebAssembly/atomics-orderings.s
index adee1a8a93a09..f493b108d6b88 100644
--- a/llvm/test/MC/WebAssembly/atomics-orderings.s
+++ b/llvm/test/MC/WebAssembly/atomics-orderings.s
@@ -1,28 +1,37 @@
# RUN: llvm-mc -no-type-check -show-encoding -triple=wasm32-unknown-unknown -mattr=+atomics,+relaxed-atomics < %s | FileCheck %s
-# RUN: llvm-mc -no-type-check -triple=wasm32-unknown-unknown -mattr=+atomics,+relaxed-atomics %s -filetype=obj -o - | llvm-objdump --no-print-imm-hex -d - | FileCheck %s --check-prefix=DISASM
+# RUN: llvm-mc -no-type-check -triple=wasm32-unknown-unknown -mattr=+atomics,+relaxed-atomics %s -filetype=obj -o - | llvm-objdump --mattr=+atomics,+relaxed-atomics --no-print-imm-hex -d - | FileCheck %s --check-prefix=DISASM
+# Ensure we can disassemble even when not explicitly enabling the feature in the disassembler.
+# In that case we will print nothing instead of "seqcst" but will still print "acqrel"
+# RUN: llvm-mc -no-type-check -triple=wasm32-unknown-unknown -mattr=+atomics,+relaxed-atomics %s -filetype=obj -o - | llvm-objdump --no-print-imm-hex -d - | FileCheck %s --check-prefix=DISASM-NOATTR
.section .text.main,"",@
main:
.functype main () -> ()
atomic.fence seqcst
- # CHECK: atomic.fence # encoding: [0xfe,0x03,0x00]
- # DISASM: atomic.fence
+ # CHECK: atomic.fence seqcst # encoding: [0xfe,0x03,0x00]
+ # DISASM: atomic.fence seqcst
+ # DISASM-NOATTR: atomic.fence {{$}}
+
atomic.fence acqrel
# CHECK: atomic.fence acqrel # encoding: [0xfe,0x03,0x01]
# DISASM: atomic.fence acqrel
+ # DISASM-NOATTR: atomic.fence acqrel
+
atomic.fence
- # CHECK: atomic.fence # encoding: [0xfe,0x03,0x00]
- # DISASM: atomic.fence
+ # CHECK: atomic.fence seqcst # encoding: [0xfe,0x03,0x00]
+ # DISASM: atomic.fence seqcst
+ # DISASM-NOATTR: atomic.fence {{$}}
+
- # CHECK: i32.atomic.load 0 # encoding: [0xfe,0x10,0x02,0x00]
- # DISASM: i32.atomic.load 0
+ # CHECK: i32.atomic.load seqcst 0 # encoding: [0xfe,0x10,0x02,0x00]
+ # DISASM: i32.atomic.load seqcst 0
i32.atomic.load 0
- # CHECK: i32.atomic.load 0 # encoding: [0xfe,0x10,0x02,0x00]
- # DISASM: i32.atomic.load 0
+ # CHECK: i32.atomic.load seqcst 0 # encoding: [0xfe,0x10,0x02,0x00]
+ # DISASM: i32.atomic.load seqcst 0
i32.atomic.load seqcst 0
# CHECK: i32.atomic.load acqrel 0 # encoding: [0xfe,0x10,0x22,0x01,0x00]
@@ -49,8 +58,8 @@ main:
# DISASM: i64.atomic.rmw.cmpxchg acqrel 0
i64.atomic.rmw.cmpxchg acqrel 0
- # CHECK: i32.atomic.load8_u 0 # encoding: [0xfe,0x12,0x00,0x00]
- # DISASM: i32.atomic.load8_u 0
+ # CHECK: i32.atomic.load8_u seqcst 0 # encoding: [0xfe,0x12,0x00,0x00]
+ # DISASM: i32.atomic.load8_u seqcst 0
i32.atomic.load8_u seqcst 0:p2align=0
# CHECK: i64.atomic.rmw32.xchg_u acqrel 0 # encoding: [0xfe,0x47,0x22,0x11,0x00]
>From 5d56e240fce33af6f07129b41764830cdb6369aa Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Wed, 4 Mar 2026 00:49:38 +0000
Subject: [PATCH 22/22] rename encodeMemArgNoOffset
---
.../MCTargetDesc/WebAssemblyMCCodeEmitter.cpp | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 48b3883413e93..43c1d00b4d81c 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -47,10 +47,11 @@ class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const override;
- void encodeMemArgNoOffset(const MCInst &MI, unsigned P2AlignIdx,
- const MCInstrDesc &Desc, const MCSubtargetInfo &STI,
- raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
- uint64_t Start) const;
+ void encodeP2AlignAndMemOrder(const MCInst &MI, unsigned P2AlignIdx,
+ const MCInstrDesc &Desc,
+ const MCSubtargetInfo &STI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ uint64_t Start) const;
uint8_t getEncodedMemOrder(uint8_t Order, unsigned Opcode) const;
@@ -75,7 +76,7 @@ uint8_t WebAssemblyMCCodeEmitter::getEncodedMemOrder(uint8_t Order,
return Order;
}
-void WebAssemblyMCCodeEmitter::encodeMemArgNoOffset(
+void WebAssemblyMCCodeEmitter::encodeP2AlignAndMemOrder(
const MCInst &MI, unsigned P2AlignIdx, const MCInstrDesc &Desc,
const MCSubtargetInfo &STI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups, uint64_t Start) const {
@@ -152,7 +153,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
encodeSLEB128(int32_t(MO.getImm()), OS);
break;
case WebAssembly::OPERAND_P2ALIGN:
- encodeMemArgNoOffset(MI, I, Desc, STI, OS, Fixups, Start);
+ encodeP2AlignAndMemOrder(MI, I, Desc, STI, OS, Fixups, Start);
break;
case WebAssembly::OPERAND_OFFSET32:
encodeULEB128(uint32_t(MO.getImm()), OS);
More information about the llvm-commits
mailing list