@@ -69,12 +69,23 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {
69
69
std::vector<unsigned > List;
70
70
};
71
71
72
+ struct CaLOpElem {
73
+ uint8_t Opcode;
74
+ const MCExpr *Tag;
75
+ unsigned Dest;
76
+ };
77
+
78
+ struct CaLOp {
79
+ std::vector<CaLOpElem> List;
80
+ };
81
+
72
82
union {
73
83
struct TokOp Tok;
74
84
struct IntOp Int;
75
85
struct FltOp Flt;
76
86
struct SymOp Sym;
77
87
struct BrLOp BrL;
88
+ struct CaLOp CaL;
78
89
};
79
90
80
91
WebAssemblyOperand (SMLoc Start, SMLoc End, TokOp T)
@@ -85,12 +96,16 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {
85
96
: Kind(Float), StartLoc(Start), EndLoc(End), Flt(F) {}
86
97
WebAssemblyOperand (SMLoc Start, SMLoc End, SymOp S)
87
98
: Kind(Symbol), StartLoc(Start), EndLoc(End), Sym(S) {}
88
- WebAssemblyOperand (SMLoc Start, SMLoc End)
89
- : Kind(BrList), StartLoc(Start), EndLoc(End), BrL() {}
99
+ WebAssemblyOperand (SMLoc Start, SMLoc End, BrLOp B)
100
+ : Kind(BrList), StartLoc(Start), EndLoc(End), BrL(B) {}
101
+ WebAssemblyOperand (SMLoc Start, SMLoc End, CaLOp C)
102
+ : Kind(CatchList), StartLoc(Start), EndLoc(End), CaL(C) {}
90
103
91
104
~WebAssemblyOperand () {
92
105
if (isBrList ())
93
106
BrL.~BrLOp ();
107
+ if (isCatchList ())
108
+ CaL.~CaLOp ();
94
109
}
95
110
96
111
bool isToken () const override { return Kind == Token; }
@@ -153,7 +168,15 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {
153
168
}
154
169
155
170
void addCatchListOperands (MCInst &Inst, unsigned N) const {
156
- // TODO
171
+ assert (N == 1 && isCatchList () && " Invalid CatchList!" );
172
+ Inst.addOperand (MCOperand::createImm (CaL.List .size ()));
173
+ for (auto Ca : CaL.List ) {
174
+ Inst.addOperand (MCOperand::createImm (Ca.Opcode ));
175
+ if (Ca.Opcode == wasm::WASM_OPCODE_CATCH ||
176
+ Ca.Opcode == wasm::WASM_OPCODE_CATCH_REF)
177
+ Inst.addOperand (MCOperand::createExpr (Ca.Tag ));
178
+ Inst.addOperand (MCOperand::createImm (Ca.Dest ));
179
+ }
157
180
}
158
181
159
182
void print (raw_ostream &OS) const override {
@@ -174,7 +197,7 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {
174
197
OS << " BrList:" << BrL.List .size ();
175
198
break ;
176
199
case CatchList:
177
- // TODO
200
+ OS << " CaList: " << CaL. List . size ();
178
201
break ;
179
202
}
180
203
}
@@ -228,6 +251,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
228
251
Loop,
229
252
Try,
230
253
CatchAll,
254
+ TryTable,
231
255
If,
232
256
Else,
233
257
Undefined,
@@ -304,6 +328,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
304
328
return {" try" , " end_try/delegate" };
305
329
case CatchAll:
306
330
return {" catch_all" , " end_try" };
331
+ case TryTable:
332
+ return {" try_table" , " end_try_table" };
307
333
case If:
308
334
return {" if" , " end_if" };
309
335
case Else:
@@ -571,6 +597,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
571
597
// proper nesting.
572
598
bool ExpectBlockType = false ;
573
599
bool ExpectFuncType = false ;
600
+ bool ExpectCatchList = false ;
574
601
std::unique_ptr<WebAssemblyOperand> FunctionTable;
575
602
if (Name == " block" ) {
576
603
push (Block);
@@ -593,12 +620,19 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
593
620
} else if (Name == " catch_all" ) {
594
621
if (popAndPushWithSameSignature (Name, Try, CatchAll))
595
622
return true ;
623
+ } else if (Name == " try_table" ) {
624
+ push (TryTable);
625
+ ExpectBlockType = true ;
626
+ ExpectCatchList = true ;
596
627
} else if (Name == " end_if" ) {
597
628
if (pop (Name, If, Else))
598
629
return true ;
599
630
} else if (Name == " end_try" ) {
600
631
if (pop (Name, Try, CatchAll))
601
632
return true ;
633
+ } else if (Name == " end_try_table" ) {
634
+ if (pop (Name, TryTable))
635
+ return true ;
602
636
} else if (Name == " delegate" ) {
603
637
if (pop (Name, Try))
604
638
return true ;
@@ -622,7 +656,18 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
622
656
ExpectFuncType = true ;
623
657
}
624
658
625
- if (ExpectFuncType || (ExpectBlockType && Lexer.is (AsmToken::LParen))) {
659
+ // Returns true if the next tokens are a catch clause
660
+ auto PeekCatchList = [&]() {
661
+ if (Lexer.isNot (AsmToken::LParen))
662
+ return false ;
663
+ AsmToken NextTok = Lexer.peekTok ();
664
+ return NextTok.getKind () == AsmToken::Identifier &&
665
+ NextTok.getIdentifier ().starts_with (" catch" );
666
+ };
667
+
668
+ // Parse a multivalue block type
669
+ if (ExpectFuncType ||
670
+ (Lexer.is (AsmToken::LParen) && ExpectBlockType && !PeekCatchList ())) {
626
671
// This has a special TYPEINDEX operand which in text we
627
672
// represent as a signature, such that we can re-build this signature,
628
673
// attach it to an anonymous symbol, which is what WasmObjectWriter
@@ -648,6 +693,23 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
648
693
Loc.getLoc (), Loc.getEndLoc (), WebAssemblyOperand::SymOp{Expr}));
649
694
}
650
695
696
+ // If we are expecting a catch clause list, try to parse it here.
697
+ //
698
+ // If there is a multivalue block return type before this catch list, it
699
+ // should have been parsed above. If there is no return type before
700
+ // encountering this catch list, this means the type is void.
701
+ // The case when there is a single block return value and then a catch list
702
+ // will be handled below in the 'while' loop.
703
+ if (ExpectCatchList && PeekCatchList ()) {
704
+ if (ExpectBlockType) {
705
+ ExpectBlockType = false ;
706
+ addBlockTypeOperand (Operands, NameLoc, WebAssembly::BlockType::Void);
707
+ }
708
+ if (parseCatchList (Operands))
709
+ return true ;
710
+ ExpectCatchList = false ;
711
+ }
712
+
651
713
while (Lexer.isNot (AsmToken::EndOfStatement)) {
652
714
auto &Tok = Lexer.getTok ();
653
715
switch (Tok.getKind ()) {
@@ -661,7 +723,15 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
661
723
if (BT == WebAssembly::BlockType::Invalid)
662
724
return error (" Unknown block type: " , Id);
663
725
addBlockTypeOperand (Operands, NameLoc, BT);
726
+ ExpectBlockType = false ;
664
727
Parser.Lex ();
728
+ // Now that we've parsed a single block return type, if we are
729
+ // expecting a catch clause list, try to parse it.
730
+ if (ExpectCatchList && PeekCatchList ()) {
731
+ if (parseCatchList (Operands))
732
+ return true ;
733
+ ExpectCatchList = false ;
734
+ }
665
735
} else {
666
736
// Assume this identifier is a label.
667
737
const MCExpr *Val;
@@ -703,8 +773,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
703
773
}
704
774
case AsmToken::LCurly: {
705
775
Parser.Lex ();
706
- auto Op =
707
- std::make_unique<WebAssemblyOperand>( Tok.getLoc (), Tok.getEndLoc ());
776
+ auto Op = std::make_unique<WebAssemblyOperand>(
777
+ Tok.getLoc (), Tok.getEndLoc (), WebAssemblyOperand::BrLOp{} );
708
778
if (!Lexer.is (AsmToken::RCurly))
709
779
for (;;) {
710
780
Op->BrL .List .push_back (Lexer.getTok ().getIntVal ());
@@ -724,10 +794,18 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
724
794
return true ;
725
795
}
726
796
}
727
- if (ExpectBlockType && Operands.size () == 1 ) {
728
- // Support blocks with no operands as default to void.
797
+
798
+ // If we are still expecting to parse a block type or a catch list at this
799
+ // point, we set them to the default/empty state.
800
+
801
+ // Support blocks with no operands as default to void.
802
+ if (ExpectBlockType)
729
803
addBlockTypeOperand (Operands, NameLoc, WebAssembly::BlockType::Void);
730
- }
804
+ // If no catch list has been parsed, add an empty catch list operand.
805
+ if (ExpectCatchList)
806
+ Operands.push_back (std::make_unique<WebAssemblyOperand>(
807
+ NameLoc, NameLoc, WebAssemblyOperand::CaLOp{}));
808
+
731
809
if (FunctionTable)
732
810
Operands.push_back (std::move (FunctionTable));
733
811
Parser.Lex ();
@@ -752,6 +830,55 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
752
830
return false ;
753
831
}
754
832
833
+ bool parseCatchList (OperandVector &Operands) {
834
+ auto Op = std::make_unique<WebAssemblyOperand>(
835
+ Lexer.getTok ().getLoc (), SMLoc (), WebAssemblyOperand::CaLOp{});
836
+ SMLoc EndLoc;
837
+
838
+ while (Lexer.is (AsmToken::LParen)) {
839
+ if (expect (AsmToken::LParen, " (" ))
840
+ return true ;
841
+
842
+ auto CatchStr = expectIdent ();
843
+ if (CatchStr.empty ())
844
+ return true ;
845
+ uint8_t CatchOpcode =
846
+ StringSwitch<uint8_t >(CatchStr)
847
+ .Case (" catch" , wasm::WASM_OPCODE_CATCH)
848
+ .Case (" catch_ref" , wasm::WASM_OPCODE_CATCH_REF)
849
+ .Case (" catch_all" , wasm::WASM_OPCODE_CATCH_ALL)
850
+ .Case (" catch_all_ref" , wasm::WASM_OPCODE_CATCH_ALL_REF)
851
+ .Default (0xff );
852
+ if (CatchOpcode == 0xff )
853
+ return error (
854
+ " Expected catch/catch_ref/catch_all/catch_all_ref, instead got: " +
855
+ CatchStr);
856
+
857
+ const MCExpr *Tag = nullptr ;
858
+ if (CatchOpcode == wasm::WASM_OPCODE_CATCH ||
859
+ CatchOpcode == wasm::WASM_OPCODE_CATCH_REF) {
860
+ if (Parser.parseExpression (Tag))
861
+ return error (" Cannot parse symbol: " , Lexer.getTok ());
862
+ }
863
+
864
+ auto &DestTok = Lexer.getTok ();
865
+ if (DestTok.isNot (AsmToken::Integer))
866
+ return error (" Expected integer constant, instead got: " , DestTok);
867
+ unsigned Dest = DestTok.getIntVal ();
868
+ Parser.Lex ();
869
+
870
+ EndLoc = Lexer.getTok ().getEndLoc ();
871
+ if (expect (AsmToken::RParen, " )" ))
872
+ return true ;
873
+
874
+ Op->CaL .List .push_back ({CatchOpcode, Tag, Dest});
875
+ }
876
+
877
+ Op->EndLoc = EndLoc;
878
+ Operands.push_back (std::move (Op));
879
+ return false ;
880
+ }
881
+
755
882
bool CheckDataSection () {
756
883
if (CurrentState != DataSection) {
757
884
auto WS = cast<MCSectionWasm>(getStreamer ().getCurrentSectionOnly ());
0 commit comments