[WebAssembly] Update InstPrinter and AsmParser for new EH instructions
authorHeejin Ahn <aheejin@gmail.com>
Fri, 1 Jan 2021 09:03:21 +0000 (01:03 -0800)
committerHeejin Ahn <aheejin@gmail.com>
Sat, 6 Feb 2021 16:54:56 +0000 (08:54 -0800)
This updates InstPrinter and AsmParser for `delegate` and `catch_all`
instructions. Both will reject programs with multiple `catch_all`s per a
single `try`. And InstPrinter uses `EHInstStack` to figure out whether
to print catch label comments: It does not print catch label comments
for second `catch` or `catch_all` in a `try`.

Reviewed By: aardappel

Differential Revision: https://reviews.llvm.org/D94051

llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
llvm/test/MC/WebAssembly/annotations.s
llvm/test/MC/WebAssembly/basic-assembly-errors.s

index 0328381..9a2ae01 100644 (file)
@@ -216,6 +216,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
     Block,
     Loop,
     Try,
+    CatchAll,
     If,
     Else,
     Undefined,
@@ -273,7 +274,9 @@ public:
     case Loop:
       return {"loop", "end_loop"};
     case Try:
-      return {"try", "end_try"};
+      return {"try", "end_try/delegate"};
+    case CatchAll:
+      return {"catch_all", "end_try"};
     case If:
       return {"if", "end_if"};
     case Else:
@@ -533,10 +536,17 @@ public:
       if (pop(Name, Try))
         return true;
       push(Try);
+    } else if (Name == "catch_all") {
+      if (pop(Name, Try))
+        return true;
+      push(CatchAll);
     } else if (Name == "end_if") {
       if (pop(Name, If, Else))
         return true;
     } else if (Name == "end_try") {
+      if (pop(Name, Try, CatchAll))
+        return true;
+    } else if (Name == "delegate") {
       if (pop(Name, Try))
         return true;
     } else if (Name == "end_loop") {
index 1df3574..c4d0f2a 100644 (file)
@@ -108,6 +108,7 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
       ControlFlowStack.push_back(std::make_pair(ControlFlowCounter, false));
       EHPadStack.push_back(ControlFlowCounter);
       DelegateStack.push_back(ControlFlowCounter++);
+      EHInstStack.push_back(TRY);
       return;
 
     case WebAssembly::END_LOOP:
@@ -133,11 +134,12 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
 
     case WebAssembly::END_TRY:
     case WebAssembly::END_TRY_S:
-      if (ControlFlowStack.empty()) {
+      if (ControlFlowStack.empty() || EHInstStack.empty()) {
         printAnnotation(OS, "End marker mismatch!");
       } else {
         printAnnotation(
             OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
+        EHInstStack.pop_back();
       }
       return;
 
@@ -145,11 +147,26 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
     case WebAssembly::CATCH_S:
     case WebAssembly::CATCH_ALL:
     case WebAssembly::CATCH_ALL_S:
-      if (EHPadStack.empty() || DelegateStack.empty()) {
+      // There can be multiple catch instructions for one try instruction, so
+      // we print a label only for the first 'catch' label.
+      if (EHInstStack.empty()) {
         printAnnotation(OS, "try-catch mismatch!");
-      } else {
-        printAnnotation(OS, "catch" + utostr(EHPadStack.pop_back_val()) + ':');
-        DelegateStack.pop_back();
+      } else if (EHInstStack.back() == CATCH_ALL) {
+        printAnnotation(OS, "catch/catch_all cannot occur after catch_all");
+      } else if (EHInstStack.back() == TRY) {
+        if (EHPadStack.empty() || DelegateStack.empty()) {
+          printAnnotation(OS, "try-catch mismatch!");
+        } else {
+          printAnnotation(OS,
+                          "catch" + utostr(EHPadStack.pop_back_val()) + ':');
+          DelegateStack.pop_back();
+        }
+        EHInstStack.pop_back();
+        if (Opc == WebAssembly::CATCH || Opc == WebAssembly::CATCH_S) {
+          EHInstStack.push_back(CATCH);
+        } else {
+          EHInstStack.push_back(CATCH_ALL);
+        }
       }
       return;
 
@@ -167,7 +184,7 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
     case WebAssembly::DELEGATE:
     case WebAssembly::DELEGATE_S:
       if (ControlFlowStack.empty() || EHPadStack.empty() ||
-          DelegateStack.empty()) {
+          DelegateStack.empty() || EHInstStack.empty()) {
         printAnnotation(OS, "try-delegate mismatch!");
       } else {
         // 'delegate' is
@@ -181,6 +198,7 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
                             ": ";
         EHPadStack.pop_back();
         DelegateStack.pop_back();
+        EHInstStack.pop_back();
         uint64_t Depth = MI->getOperand(0).getImm();
         if (Depth >= DelegateStack.size()) {
           Label += "to caller";
index e0306bb..5c6f977 100644 (file)
@@ -33,6 +33,9 @@ class WebAssemblyInstPrinter final : public MCInstPrinter {
   // separate stack for 'delegate'.
   SmallVector<uint64_t, 4> DelegateStack;
 
+  enum EHInstKind { TRY, CATCH, CATCH_ALL };
+  SmallVector<EHInstKind, 4> EHInstStack;
+
 public:
   WebAssemblyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
                          const MCRegisterInfo &MRI);
index 04c3eef..9a797a1 100644 (file)
@@ -21,9 +21,12 @@ test_annotation:
   try
   rethrow   0
   catch     __cpp_exception
+  catch_all
   block
   try
   br        0
+  try
+  delegate  1
   catch_all
   end_try
   end_block
@@ -46,9 +49,12 @@ test_annotation:
 # CHECK-NEXT:   try
 # CHECK-NEXT:   rethrow   0               # down to catch3
 # CHECK-NEXT:   catch     __cpp_exception # catch3:
+# CHECK-NEXT:   catch_all{{$}}
 # CHECK-NEXT:   block
 # CHECK-NEXT:   try
 # CHECK-NEXT:   br        0               # 0: down to label5
+# CHECK-NEXT:   try
+# CHECK-NEXT:   delegate    1             # label/catch6: down to catch4
 # CHECK-NEXT:   catch_all                 # catch5:
 # CHECK-NEXT:   end_try                   # label5:
 # CHECK-NEXT:   end_block                 # label4:
index 45a0965..24002ef 100644 (file)
@@ -18,8 +18,16 @@ test0:
 # CHECK: Block construct type mismatch, expected: end_block, instead got: end_if
     end_if
     try
+# CHECK: Block construct type mismatch, expected: end_try/delegate, instead got: end_block
+    end_block
     loop
-# CHECK: Block construct type mismatch, expected: end_loop, instead got: end_function
+    try
+    catch_all
+    catch_all
+# CHECK: error: Block construct type mismatch, expected: end_try, instead got: catch_all
+    end
+# CHECK: Block construct type mismatch, expected: end_try, instead got: end_function
+# CHECK: error: Unmatched block construct(s) at function end: catch_all
 # CHECK: error: Unmatched block construct(s) at function end: loop
 # CHECK: error: Unmatched block construct(s) at function end: try
 # CHECK: error: Unmatched block construct(s) at function end: block