[llvm] db1dac1 - [WebAssembly] `AsmTypeCheck` support to br instr
Congcong Cai via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 13 02:56:38 PDT 2023
Author: Congcong Cai
Date: 2023-04-13T11:56:11+02:00
New Revision: db1dac1e20bd0bf37cda4915462101b6d7e04dd7
URL: https://github.com/llvm/llvm-project/commit/db1dac1e20bd0bf37cda4915462101b6d7e04dd7
DIFF: https://github.com/llvm/llvm-project/commit/db1dac1e20bd0bf37cda4915462101b6d7e04dd7.diff
LOG: [WebAssembly] `AsmTypeCheck` support to br instr
This PR introduces the `BrStack` member to store the info about
`loop`, `block`, `if` and `try`. It can check whether `br` immediate number
out of range.
Reviewed By: aheejin
Differential Revision: https://reviews.llvm.org/D148054
Added:
llvm/test/MC/WebAssembly/type-checker-br.s
Modified:
llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
llvm/test/MC/WebAssembly/type-checker-errors.s
Removed:
################################################################################
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
index 8aa538b08d27f..bc0cb2d10cdbc 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
@@ -51,6 +51,7 @@ WebAssemblyAsmTypeCheck::WebAssemblyAsmTypeCheck(MCAsmParser &Parser,
void WebAssemblyAsmTypeCheck::funcDecl(const wasm::WasmSignature &Sig) {
LocalTypes.assign(Sig.Params.begin(), Sig.Params.end());
ReturnTypes.assign(Sig.Returns.begin(), Sig.Returns.end());
+ BrStack.emplace_back(Sig.Returns.begin(), Sig.Returns.end());
}
void WebAssemblyAsmTypeCheck::localDecl(
@@ -122,7 +123,36 @@ bool WebAssemblyAsmTypeCheck::getLocal(SMLoc ErrorLoc, const MCInst &Inst,
return false;
}
+static std::optional<std::string>
+checkStackTop(const SmallVectorImpl<wasm::ValType> &ExpectedStackTop,
+ const SmallVectorImpl<wasm::ValType> &Got) {
+ for (size_t I = 0; I < ExpectedStackTop.size(); I++) {
+ auto EVT = ExpectedStackTop[I];
+ auto PVT = Got[Got.size() - ExpectedStackTop.size() + I];
+ if (PVT != EVT)
+ return std::string{"got "} + WebAssembly::typeToString(PVT) +
+ ", expected " + WebAssembly::typeToString(EVT);
+ }
+ return std::nullopt;
+}
+
+bool WebAssemblyAsmTypeCheck::checkBr(SMLoc ErrorLoc, size_t Level) {
+ if (Level >= BrStack.size())
+ return typeError(ErrorLoc,
+ StringRef("br: invalid depth ") + std::to_string(Level));
+ const SmallVector<wasm::ValType, 4> &Expected =
+ BrStack[BrStack.size() - Level - 1];
+ if (Expected.size() > Stack.size())
+ return typeError(ErrorLoc, "br: insufficient values on the type stack");
+ auto IsStackTopInvalid = checkStackTop(Expected, Stack);
+ if (IsStackTopInvalid)
+ return typeError(ErrorLoc, "br " + IsStackTopInvalid.value());
+ return false;
+}
+
bool WebAssemblyAsmTypeCheck::checkEnd(SMLoc ErrorLoc, bool PopVals) {
+ if (!PopVals)
+ BrStack.pop_back();
if (LastSig.Returns.size() > Stack.size())
return typeError(ErrorLoc, "end: insufficient values on the type stack");
@@ -134,14 +164,9 @@ bool WebAssemblyAsmTypeCheck::checkEnd(SMLoc ErrorLoc, bool PopVals) {
return false;
}
- for (size_t i = 0; i < LastSig.Returns.size(); i++) {
- auto EVT = LastSig.Returns[i];
- auto PVT = Stack[Stack.size() - LastSig.Returns.size() + i];
- if (PVT != EVT)
- return typeError(ErrorLoc,
- StringRef("end got ") + WebAssembly::typeToString(PVT) +
- ", expected " + WebAssembly::typeToString(EVT));
- }
+ auto IsStackTopInvalid = checkStackTop(LastSig.Returns, Stack);
+ if (IsStackTopInvalid)
+ return typeError(ErrorLoc, "end " + IsStackTopInvalid.value());
return false;
}
@@ -300,6 +325,14 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst,
} else if (Name == "drop") {
if (popType(ErrorLoc, {}))
return true;
+ } else if (Name == "try" || Name == "block" || Name == "loop" ||
+ Name == "if") {
+ if (Name == "if" && popType(ErrorLoc, wasm::ValType::I32))
+ return true;
+ if (Name == "loop")
+ BrStack.emplace_back(LastSig.Params.begin(), LastSig.Params.end());
+ else
+ BrStack.emplace_back(LastSig.Returns.begin(), LastSig.Returns.end());
} else if (Name == "end_block" || Name == "end_loop" || Name == "end_if" ||
Name == "else" || Name == "end_try" || Name == "catch" ||
Name == "catch_all" || Name == "delegate") {
@@ -321,6 +354,12 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst,
// "params" part
Stack.insert(Stack.end(), Sig->Params.begin(), Sig->Params.end());
}
+ } else if (Name == "br") {
+ const MCOperand &Operand = Inst.getOperand(0);
+ if (!Operand.isImm())
+ return false;
+ if (checkBr(ErrorLoc, static_cast<size_t>(Operand.getImm())))
+ return true;
} else if (Name == "return") {
if (endOfFunction(ErrorLoc))
return true;
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
index fb298c2a11260..6fa95c3929753 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
@@ -29,6 +29,7 @@ class WebAssemblyAsmTypeCheck final {
const MCInstrInfo &MII;
SmallVector<wasm::ValType, 8> Stack;
+ SmallVector<SmallVector<wasm::ValType, 4>, 8> BrStack;
SmallVector<wasm::ValType, 16> LocalTypes;
SmallVector<wasm::ValType, 4> ReturnTypes;
wasm::WasmSignature LastSig;
@@ -42,6 +43,7 @@ class WebAssemblyAsmTypeCheck final {
bool popRefType(SMLoc ErrorLoc);
bool getLocal(SMLoc ErrorLoc, const MCInst &Inst, wasm::ValType &Type);
bool checkEnd(SMLoc ErrorLoc, bool PopVals = false);
+ bool checkBr(SMLoc ErrorLoc, size_t Level);
bool checkSig(SMLoc ErrorLoc, const wasm::WasmSignature &Sig);
bool getSymRef(SMLoc ErrorLoc, const MCInst &Inst,
const MCSymbolRefExpr *&SymRef);
@@ -60,6 +62,7 @@ class WebAssemblyAsmTypeCheck final {
void Clear() {
Stack.clear();
+ BrStack.clear();
LocalTypes.clear();
ReturnTypes.clear();
TypeErrorThisFunction = false;
diff --git a/llvm/test/MC/WebAssembly/type-checker-br.s b/llvm/test/MC/WebAssembly/type-checker-br.s
new file mode 100644
index 0000000000000..df3f88f9685e1
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/type-checker-br.s
@@ -0,0 +1,25 @@
+# RUN: llvm-mc -triple=wasm32 %s 2>&1
+
+br_block:
+ .functype br_block () -> ()
+ block f32
+ block i32
+ f32.const 1.0
+ br 1
+ drop
+ i32.const 1
+ end_block
+ drop
+ f32.const 1.0
+ end_block
+ drop
+ end_function
+
+br_func:
+ .functype br_block () -> ()
+ block i32
+ br 1
+ i32.const 1
+ end_block
+ drop
+ end_function
diff --git a/llvm/test/MC/WebAssembly/type-checker-errors.s b/llvm/test/MC/WebAssembly/type-checker-errors.s
index 87f88c87967c6..1501bedec393c 100644
--- a/llvm/test/MC/WebAssembly/type-checker-errors.s
+++ b/llvm/test/MC/WebAssembly/type-checker-errors.s
@@ -698,3 +698,110 @@ check_after_unreachable_within_try_4:
# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value
drop
end_function
+
+br_invalid_type_loop:
+ .functype br_invalid_type_loop () -> ()
+ i32.const 1
+ loop (i32) -> (f32)
+ drop
+ f32.const 1.0
+# CHECK: :[[@LINE+1]]:5: error: br got f32, expected i32
+ br 0
+ end_loop
+ drop
+ end_function
+
+br_invalid_type_block:
+ .functype br_invalid_type_block () -> ()
+ i32.const 1
+ block (i32) -> (f32)
+# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32
+ br 0
+ f32.const 1.0
+ end_block
+ drop
+ end_function
+
+br_invalid_type_if:
+ .functype br_invalid_type_if () -> ()
+ i32.const 1
+ if f32
+ f32.const 1.0
+ else
+ i32.const 1
+# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32
+ br 0
+ end_if
+ drop
+ end_function
+
+br_invalid_type_try:
+ .functype br_invalid_type_try () -> ()
+ try f32
+ i32.const 1
+# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32
+ br 0
+ catch tag_f32
+ end_try
+ drop
+ end_function
+
+br_invalid_type_catch:
+ .functype br_invalid_type_catch () -> ()
+ try f32
+ f32.const 1.0
+ catch tag_i32
+# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32
+ br 0
+ end_try
+ drop
+ end_function
+
+br_invalid_type_catch_all:
+ .functype br_invalid_type_catch_all () -> ()
+ try f32
+ f32.const 1.0
+ catch_all
+ i32.const 1
+# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32
+ br 0
+ end_try
+ drop
+ end_function
+
+br_invalid_depth_out_of_range:
+ .functype br_invalid_depth_out_of_range () -> ()
+ block
+ block
+ block
+# CHECK: :[[@LINE+1]]:5: error: br: invalid depth 4
+ br 4
+ end_block
+ end_block
+ end_block
+ end_function
+
+br_incorrect_signature:
+ .functype br_incorrect_signature () -> ()
+ block f32
+ block i32
+ i32.const 1
+# CHECK: :[[@LINE+1]]:7: error: br got i32, expected f32
+ br 1
+ end_block
+ drop
+ f32.const 1.0
+ end_block
+ drop
+ end_function
+
+br_incorrect_func_signature:
+ .functype br_incorrect_func_signature () -> (i32)
+ block f32
+ f32.const 1.0
+# CHECK: :[[@LINE+1]]:5: error: br got f32, expected i32
+ br 1
+ end_block
+ drop
+ i32.const 1
+ end_function
More information about the llvm-commits
mailing list