[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