diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -190,6 +190,7 @@ Block, Loop, Try, + CatchAll, If, Else, Undefined, @@ -250,7 +251,9 @@ 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: @@ -509,10 +512,17 @@ 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") { diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h @@ -33,6 +33,9 @@ // separate stack for 'delegate'. SmallVector DelegateStack; + enum EHInstKind { TRY, CATCH, CATCH_ALL }; + SmallVector EHInstStack; + public: WebAssemblyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, const MCRegisterInfo &MRI); diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp @@ -108,6 +108,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ ": "; EHPadStack.pop_back(); DelegateStack.pop_back(); + EHInstStack.pop_back(); uint64_t Depth = MI->getOperand(0).getImm(); if (Depth >= DelegateStack.size()) { Label += "to caller"; diff --git a/llvm/test/MC/WebAssembly/annotations.s b/llvm/test/MC/WebAssembly/annotations.s --- a/llvm/test/MC/WebAssembly/annotations.s +++ b/llvm/test/MC/WebAssembly/annotations.s @@ -21,9 +21,12 @@ 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 @@ # 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: diff --git a/llvm/test/MC/WebAssembly/basic-assembly-errors.s b/llvm/test/MC/WebAssembly/basic-assembly-errors.s --- a/llvm/test/MC/WebAssembly/basic-assembly-errors.s +++ b/llvm/test/MC/WebAssembly/basic-assembly-errors.s @@ -14,8 +14,16 @@ # 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