[llvm] ac65366 - [WebAssembly] support "return" and unreachable code in asm type checker
Wouter van Oortmerssen via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 1 15:43:28 PDT 2021
Author: Wouter van Oortmerssen
Date: 2021-11-01T15:42:58-07:00
New Revision: ac65366485d4584c9e7f39a59bc56d833627c1ea
URL: https://github.com/llvm/llvm-project/commit/ac65366485d4584c9e7f39a59bc56d833627c1ea
DIFF: https://github.com/llvm/llvm-project/commit/ac65366485d4584c9e7f39a59bc56d833627c1ea.diff
LOG: [WebAssembly] support "return" and unreachable code in asm type checker
To support return (it not being supported well was the ground cause for
https://github.com/WebAssembly/wasi-sdk/issues/200) we also have to have
at least a basic notion of unreachable, which in this case just means to stop
type checking until there is an end_block (an incoming control flow edge).
This is conservative (may miss on some type checking opportunities) but is
simple and an improvement over what we had before.
Differential Revision: https://reviews.llvm.org/D112953
Added:
Modified:
llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
llvm/test/MC/WebAssembly/basic-assembly.s
Removed:
################################################################################
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 77898238b2632..7d1e6c553f812 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -1114,6 +1114,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
void onEndOfFunction(SMLoc ErrorLoc) {
TC.endOfFunction(ErrorLoc);
+ // Reset the type checker state.
+ TC.Clear();
// Automatically output a .size directive, so it becomes optional for the
// user.
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
index 9e4162a969cb9..a6b5d4252f2f9 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
@@ -74,6 +74,9 @@ bool WebAssemblyAsmTypeCheck::typeError(SMLoc ErrorLoc, const Twine &Msg) {
// which are mostly not helpful.
if (TypeErrorThisFunction)
return true;
+ // If we're currently in unreachable code, we surpress errors as well.
+ if (Unreachable)
+ return true;
TypeErrorThisFunction = true;
dumpTypeStack("current stack: ");
return Parser.Error(ErrorLoc, Msg);
@@ -170,17 +173,18 @@ bool WebAssemblyAsmTypeCheck::getGlobal(SMLoc ErrorLoc, const MCInst &Inst,
return false;
}
-void WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc) {
+bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc) {
// Check the return types.
for (auto RVT : llvm::reverse(ReturnTypes)) {
- popType(ErrorLoc, RVT);
+ if (popType(ErrorLoc, RVT))
+ return true;
}
if (!Stack.empty()) {
- typeError(ErrorLoc,
- std::to_string(Stack.size()) + " superfluous return values");
+ return typeError(ErrorLoc, std::to_string(Stack.size()) +
+ " superfluous return values");
}
- // Reset the type checker state.
- Clear();
+ Unreachable = true;
+ return false;
}
bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst) {
@@ -219,10 +223,17 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst) {
Name == "else" || Name == "end_try") {
if (checkEnd(ErrorLoc))
return true;
+ if (Name == "end_block")
+ Unreachable = false;
+ } else if (Name == "return") {
+ if (endOfFunction(ErrorLoc))
+ return true;
} else if (Name == "call_indirect" || Name == "return_call_indirect") {
// Function value.
if (popType(ErrorLoc, wasm::ValType::I32)) return true;
if (checkSig(ErrorLoc, LastSig)) return true;
+ if (Name == "return_call_indirect" && endOfFunction(ErrorLoc))
+ return true;
} else if (Name == "call" || Name == "return_call") {
const MCSymbolRefExpr *SymRef;
if (getSymRef(ErrorLoc, Inst, SymRef))
@@ -233,6 +244,8 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst) {
return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +
" missing .functype");
if (checkSig(ErrorLoc, *Sig)) return true;
+ if (Name == "return_call" && endOfFunction(ErrorLoc))
+ return true;
} else if (Name == "catch") {
const MCSymbolRefExpr *SymRef;
if (getSymRef(ErrorLoc, Inst, SymRef))
@@ -248,6 +261,8 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst) {
} else if (Name == "ref.null") {
auto VT = static_cast<wasm::ValType>(Inst.getOperand(0).getImm());
Stack.push_back(VT);
+ } else if (Name == "unreachable") {
+ Unreachable = true;
} else {
// The current instruction is a stack instruction which doesn't have
// explicit operands that indicate push/pop types, so we get those from
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
index a15a69b504180..aa35213ccca3b 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
@@ -32,15 +32,9 @@ class WebAssemblyAsmTypeCheck final {
SmallVector<wasm::ValType, 4> ReturnTypes;
wasm::WasmSignature LastSig;
bool TypeErrorThisFunction = false;
+ bool Unreachable = false;
bool is64;
- void Clear() {
- Stack.clear();
- LocalTypes.clear();
- ReturnTypes.clear();
- TypeErrorThisFunction = false;
- }
-
void dumpTypeStack(Twine Msg);
bool typeError(SMLoc ErrorLoc, const Twine &Msg);
bool popType(SMLoc ErrorLoc, Optional<wasm::ValType> EVT);
@@ -57,8 +51,16 @@ class WebAssemblyAsmTypeCheck final {
void funcDecl(const wasm::WasmSignature &Sig);
void localDecl(const SmallVector<wasm::ValType, 4> &Locals);
void setLastSig(const wasm::WasmSignature &Sig) { LastSig = Sig; }
- void endOfFunction(SMLoc ErrorLoc);
+ bool endOfFunction(SMLoc ErrorLoc);
bool typeCheck(SMLoc ErrorLoc, const MCInst &Inst);
+
+ void Clear() {
+ Stack.clear();
+ LocalTypes.clear();
+ ReturnTypes.clear();
+ TypeErrorThisFunction = false;
+ Unreachable = false;
+ }
};
} // end namespace llvm
diff --git a/llvm/test/MC/WebAssembly/basic-assembly.s b/llvm/test/MC/WebAssembly/basic-assembly.s
index 44640824504da..b86172ba9e24c 100644
--- a/llvm/test/MC/WebAssembly/basic-assembly.s
+++ b/llvm/test/MC/WebAssembly/basic-assembly.s
@@ -1,9 +1,10 @@
-# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types,atomics,+simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+tail-call,+reference-types,atomics,+simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
# Check that it converts to .o without errors, but don't check any output:
-# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+reference-types,+atomics,+simd128,+nontrapping-fptoint,+exception-handling -o %t.o < %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+tail-call,+reference-types,+atomics,+simd128,+nontrapping-fptoint,+exception-handling -o %t.o < %s
.functype something1 () -> ()
.functype something2 (i64) -> (i32, f64)
+.functype something3 () -> (i32)
.globaltype __stack_pointer, i32
empty_func:
@@ -86,6 +87,17 @@ test0:
else
end_if
drop
+ block void
+ i32.const 2
+ return
+ end_block
+ block void
+ return_call something3
+ end_block
+ block void
+ i32.const 3
+ return_call_indirect () -> (i32)
+ end_block
local.get 4
local.get 5
f32x4.add
@@ -215,6 +227,17 @@ empty_fref_table:
# CHECK-NEXT: else
# CHECK-NEXT: end_if
# CHECK-NEXT: drop
+# CHECK-NEXT: block
+# CHECK-NEXT: i32.const 2
+# CHECK-NEXT: return
+# CHECK-NEXT: end_block
+# CHECK-NEXT: block
+# CHECK-NEXT: return_call something3
+# CHECK-NEXT: end_block
+# CHECK-NEXT: block
+# CHECK-NEXT: i32.const 3
+# CHECK-NEXT: return_call_indirect __indirect_function_table, () -> (i32)
+# CHECK-NEXT: end_block
# CHECK-NEXT: local.get 4
# CHECK-NEXT: local.get 5
# CHECK-NEXT: f32x4.add
More information about the llvm-commits
mailing list