LLVM: lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
37
38using namespace llvm;
39
40#define DEBUG_TYPE "wasm-asm-parser"
41
43
44namespace {
45
46
47
49 enum KindTy { Token, Integer, Float, Symbol, BrList, CatchList } Kind;
50
51 SMLoc StartLoc, EndLoc;
52
53 struct TokOp {
54 StringRef Tok;
55 };
56
57 struct IntOp {
58 int64_t Val;
59 };
60
61 struct FltOp {
62 double Val;
63 };
64
65 struct SymOp {
66 const MCExpr *Exp;
67 };
68
69 struct BrLOp {
70 std::vector List;
71 };
72
73 struct CaLOpElem {
74 uint8_t Opcode;
75 const MCExpr *Tag;
76 unsigned Dest;
77 };
78
79 struct CaLOp {
80 std::vector List;
81 };
82
83 union {
84 struct TokOp Tok;
85 struct IntOp Int;
86 struct FltOp Flt;
87 struct SymOp Sym;
88 struct BrLOp BrL;
89 struct CaLOp CaL;
90 };
91
92 WebAssemblyOperand(SMLoc Start, SMLoc End, TokOp T)
93 : Kind(Token), StartLoc(Start), EndLoc(End), Tok(T) {}
94 WebAssemblyOperand(SMLoc Start, SMLoc End, IntOp I)
95 : Kind(Integer), StartLoc(Start), EndLoc(End), Int(I) {}
96 WebAssemblyOperand(SMLoc Start, SMLoc End, FltOp F)
97 : Kind(Float), StartLoc(Start), EndLoc(End), Flt(F) {}
98 WebAssemblyOperand(SMLoc Start, SMLoc End, SymOp S)
99 : Kind(Symbol), StartLoc(Start), EndLoc(End), Sym(S) {}
100 WebAssemblyOperand(SMLoc Start, SMLoc End, BrLOp B)
101 : Kind(BrList), StartLoc(Start), EndLoc(End), BrL(B) {}
102 WebAssemblyOperand(SMLoc Start, SMLoc End, CaLOp C)
103 : Kind(CatchList), StartLoc(Start), EndLoc(End), CaL(C) {}
104
105 ~WebAssemblyOperand() override {
106 if (isBrList())
107 BrL.~BrLOp();
108 if (isCatchList())
109 CaL.~CaLOp();
110 }
111
112 bool isToken() const override { return Kind == Token; }
113 bool isImm() const override { return Kind == Integer || Kind == Symbol; }
114 bool isFPImm() const { return Kind == Float; }
115 bool isMem() const override { return false; }
116 bool isReg() const override { return false; }
117 bool isBrList() const { return Kind == BrList; }
118 bool isCatchList() const { return Kind == CatchList; }
119
120 MCRegister getReg() const override {
122 return 0;
123 }
124
127 return Tok.Tok;
128 }
129
130 SMLoc getStartLoc() const override { return StartLoc; }
131 SMLoc getEndLoc() const override { return EndLoc; }
132
133 void addRegOperands(MCInst &, unsigned) const {
134
135 llvm_unreachable("Assembly matcher creates register operands");
136 }
137
138 void addImmOperands(MCInst &Inst, unsigned N) const {
139 assert(N == 1 && "Invalid number of operands!");
140 if (Kind == Integer)
142 else if (Kind == Symbol)
144 else
146 }
147
148 void addFPImmf32Operands(MCInst &Inst, unsigned N) const {
149 assert(N == 1 && "Invalid number of operands!");
150 if (Kind == Float)
153 else
155 }
156
157 void addFPImmf64Operands(MCInst &Inst, unsigned N) const {
158 assert(N == 1 && "Invalid number of operands!");
159 if (Kind == Float)
161 else
163 }
164
165 void addBrListOperands(MCInst &Inst, unsigned N) const {
166 assert(N == 1 && isBrList() && "Invalid BrList!");
167 for (auto Br : BrL.List)
169 }
170
171 void addCatchListOperands(MCInst &Inst, unsigned N) const {
172 assert(N == 1 && isCatchList() && "Invalid CatchList!");
174 for (auto Ca : CaL.List) {
180 }
181 }
182
183 void print(raw_ostream &OS, const MCAsmInfo &MAI) const override {
184 switch (Kind) {
185 case Token:
186 OS << "Tok:" << Tok.Tok;
187 break;
188 case Integer:
189 OS << "Int:" << Int.Val;
190 break;
191 case Float:
192 OS << "Flt:" << Flt.Val;
193 break;
194 case Symbol:
195 OS << "Sym:" << Sym.Exp;
196 break;
197 case BrList:
198 OS << "BrList:" << BrL.List.size();
199 break;
200 case CatchList:
201 OS << "CaList:" << CaL.List.size();
202 break;
203 }
204 }
205};
206
207
210}
211
214 bool Is64) {
215 auto *Sym = static_cast<MCSymbolWasm *>(Ctx.lookupSymbol(Name));
216 if (Sym) {
217 if (!Sym->isFunctionTable())
218 Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
219 } else {
220 Sym = static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(Name));
222
223 }
224 return Sym;
225}
226
228 MCAsmParser &Parser;
229 AsmLexer &Lexer;
230
231
232
233
234
235
236
237 enum ParserState {
238 FileStart,
239 FunctionLabel,
240 FunctionStart,
241 FunctionLocals,
242 Instructions,
243 EndFunction,
244 DataSection,
245 } CurrentState = FileStart;
246
247
248 enum NestingType {
249 Function,
250 Block,
251 Loop,
252 Try,
253 CatchAll,
254 TryTable,
255 If,
256 Else,
257 Undefined,
258 };
259 struct Nested {
260 NestingType NT;
261 wasm::WasmSignature Sig;
262 };
263 std::vector NestingStack;
264
265 MCSymbolWasm *DefaultFunctionTable = nullptr;
266 MCSymbol *LastFunctionLabel = nullptr;
267
268 bool Is64;
269
270 WebAssemblyAsmTypeCheck TC;
271
272 bool SkipTypeCheck;
273
274public:
275 WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
276 const MCInstrInfo &MII, const MCTargetOptions &Options)
277 : MCTargetAsmParser(Options, STI, MII), Parser(Parser),
278 Lexer(Parser.getLexer()), Is64(STI.getTargetTriple().isArch64Bit()),
279 TC(Parser, MII, Is64), SkipTypeCheck(Options.MCNoTypeCheck) {
280 FeatureBitset FBS = ComputeAvailableFeatures(STI.getFeatureBits());
281
282
283 if (FBS.test(WebAssembly::FeatureBulkMemory)) {
284 FBS.set(WebAssembly::FeatureBulkMemoryOpt);
285 }
286
287 if (FBS.test(WebAssembly::FeatureReferenceTypes)) {
288 FBS.set(WebAssembly::FeatureCallIndirectOverlong);
289 }
290
291 setAvailableFeatures(FBS);
292
293
294 auto &SM = Parser.getSourceManager();
295 auto BufferName =
296 SM.getBufferInfo(SM.getMainFileID()).Buffer->getBufferIdentifier();
297 if (BufferName == "")
298 SkipTypeCheck = true;
299 }
300
301 void Initialize(MCAsmParser &Parser) override {
303
305 getContext(), "__indirect_function_table", Is64);
306 if (!STI->checkFeatures("+call-indirect-overlong") &&
308 DefaultFunctionTable->setOmitFromLinkingSection();
309 }
310
311#define GET_ASSEMBLER_HEADER
312#include "WebAssemblyGenAsmMatcher.inc"
313
314
317 }
318 ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
319 SMLoc &EndLoc) override {
321 }
322
323 bool error(const Twine &Msg, const AsmToken &Tok) {
324 return Parser.Error(Tok.getLoc(), Msg + Tok.getString());
325 }
326
327 bool error(const Twine &Msg, SMLoc Loc = SMLoc()) {
328 return Parser.Error(Loc.isValid() ? Loc : Lexer.getTok().getLoc(), Msg);
329 }
330
331 std::pair<StringRef, StringRef> nestingString(NestingType NT) {
332 switch (NT) {
333 case Function:
334 return {"function", "end_function"};
335 case Block:
336 return {"block", "end_block"};
337 case Loop:
338 return {"loop", "end_loop"};
339 case Try:
340 return {"try", "end_try/delegate"};
341 case CatchAll:
342 return {"catch_all", "end_try"};
343 case TryTable:
344 return {"try_table", "end_try_table"};
345 case If:
346 return {"if", "end_if"};
347 case Else:
348 return {"else", "end_if"};
349 default:
351 }
352 }
353
354 void push(NestingType NT, wasm::WasmSignature Sig = wasm::WasmSignature()) {
355 NestingStack.push_back({NT, Sig});
356 }
357
358 bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) {
359 if (NestingStack.empty())
360 return error(Twine("End of block construct with no start: ") + Ins);
361 auto Top = NestingStack.back();
362 if (Top.NT != NT1 && Top.NT != NT2)
363 return error(Twine("Block construct type mismatch, expected: ") +
364 nestingString(Top.NT).second + ", instead got: " + Ins);
365 TC.setLastSig(Top.Sig);
366 NestingStack.pop_back();
367 return false;
368 }
369
370
371
372 bool popAndPushWithSameSignature(StringRef Ins, NestingType PopNT,
373 NestingType PushNT) {
374 if (NestingStack.empty())
375 return error(Twine("End of block construct with no start: ") + Ins);
376 auto Sig = NestingStack.back().Sig;
377 if (pop(Ins, PopNT))
378 return true;
379 push(PushNT, Sig);
380 return false;
381 }
382
383 bool ensureEmptyNestingStack(SMLoc Loc = SMLoc()) {
384 auto Err = !NestingStack.empty();
385 while (!NestingStack.empty()) {
386 error(Twine("Unmatched block construct(s) at function end: ") +
387 nestingString(NestingStack.back().NT).first,
388 Loc);
389 NestingStack.pop_back();
390 }
391 return Err;
392 }
393
395 auto Ok = Lexer.is(Kind);
396 if (Ok)
397 Parser.Lex();
398 return Ok;
399 }
400
402 if (!isNext(Kind))
403 return error(std::string("Expected ") + KindName + ", instead got: ",
404 Lexer.getTok());
405 return false;
406 }
407
408 StringRef expectIdent() {
410 error("Expected identifier, got: ", Lexer.getTok());
411 return StringRef();
412 }
413 auto Name = Lexer.getTok().getString();
414 Parser.Lex();
416 }
417
418 bool parseRegTypeList(SmallVectorImplwasm::ValType &Types) {
422 return error("unknown type: ", Lexer.getTok());
424 Parser.Lex();
426 break;
427 }
428 return false;
429 }
430
431 void parseSingleInteger(bool IsNegative, OperandVector &Operands) {
432 auto &Int = Lexer.getTok();
433 int64_t Val = Int.getIntVal();
434 if (IsNegative)
435 Val = -Val;
436 Operands.push_back(std::make_unique(
437 Int.getLoc(), Int.getEndLoc(), WebAssemblyOperand::IntOp{Val}));
438 Parser.Lex();
439 }
440
441 bool parseSingleFloat(bool IsNegative, OperandVector &Operands) {
442 auto &Flt = Lexer.getTok();
443 double Val;
444 if (Flt.getString().getAsDouble(Val, false))
445 return error("Cannot parse real: ", Flt);
446 if (IsNegative)
447 Val = -Val;
448 Operands.push_back(std::make_unique(
449 Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val}));
450 Parser.Lex();
451 return false;
452 }
453
454 bool parseSpecialFloatMaybe(bool IsNegative, OperandVector &Operands) {
456 return true;
457 auto &Flt = Lexer.getTok();
458 auto S = Flt.getString();
459 double Val;
460 if (S.compare_insensitive("infinity") == 0) {
461 Val = std::numeric_limits::infinity();
462 } else if (S.compare_insensitive("nan") == 0) {
463 Val = std::numeric_limits::quiet_NaN();
464 } else {
465 return true;
466 }
467 if (IsNegative)
468 Val = -Val;
469 Operands.push_back(std::make_unique(
470 Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val}));
471 Parser.Lex();
472 return false;
473 }
474
475 bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {
476
477 auto IsLoadStore = InstName.contains(".load") ||
478 InstName.contains(".store") ||
479 InstName.contains("prefetch");
480 auto IsAtomic = InstName.contains("atomic.");
481 if (IsLoadStore || IsAtomic) {
482
484 auto Id = expectIdent();
485 if (Id != "p2align")
486 return error("Expected p2align, instead got: " + Id);
488 return true;
490 return error("Expected integer constant");
491 parseSingleInteger(false, Operands);
492 } else {
493
494
495
496 auto IsLoadStoreLane = InstName.contains("_lane");
497 if (IsLoadStoreLane && Operands.size() == 4)
498 return false;
499
500
501
502
503 auto Tok = Lexer.getTok();
504 Operands.push_back(std::make_unique(
505 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));
506 }
507 }
508 return false;
509 }
510
511 void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
513 if (BT == WebAssembly::BlockType::Void) {
514 TC.setLastSig(wasm::WasmSignature{});
515 } else {
516 wasm::WasmSignature Sig({static_cast<wasm::ValType>(BT)}, {});
517 TC.setLastSig(Sig);
518 NestingStack.back().Sig = Sig;
519 }
520 Operands.push_back(std::make_unique(
521 NameLoc, NameLoc, WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
522 }
523
524 bool parseLimits(wasm::WasmLimits *Limits) {
525 auto Tok = Lexer.getTok();
527 return error("Expected integer constant, instead got: ", Tok);
531 Parser.Lex();
532
535 auto Tok = Lexer.getTok();
537 return error("Expected integer constant, instead got: ", Tok);
541 Parser.Lex();
542 }
543 return false;
544 }
545
546 bool parseFunctionTableOperand(std::unique_ptr *Op) {
547 if (STI->checkFeatures("+call-indirect-overlong") ||
549
550
551
552
553
554 auto &Tok = Lexer.getTok();
556 auto *Sym =
559 *Op = std::make_unique(
560 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::SymOp{Val});
561 Parser.Lex();
563 }
564 const auto *Val =
566 *Op = std::make_unique(
567 SMLoc(), SMLoc(), WebAssemblyOperand::SymOp{Val});
568 return false;
569 }
570
571
572
573 getStreamer().emitSymbolAttribute(DefaultFunctionTable, MCSA_NoDeadStrip);
574 *Op = std::make_unique(SMLoc(), SMLoc(),
575 WebAssemblyOperand::IntOp{0});
576 return false;
577 }
578
579 bool parseInstruction(ParseInstructionInfo & , StringRef Name,
580 SMLoc NameLoc, OperandVector &Operands) override {
581
582
584
585
586
587
588 for (;;) {
589 auto &Sep = Lexer.getTok();
590 if (Sep.getLoc().getPointer() != Name.end() ||
592 break;
593
594 Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());
595 Parser.Lex();
596
597 auto &Id = Lexer.getTok();
599 Id.getLoc().getPointer() != Name.end())
600 return error("Incomplete instruction name: ", Id);
601 Name = StringRef(Name.begin(), Name.size() + Id.getString().size());
602 Parser.Lex();
603 }
604
605
606 Operands.push_back(std::make_unique(
608 WebAssemblyOperand::TokOp{Name}));
609
610
611
612 bool ExpectBlockType = false;
613 bool ExpectFuncType = false;
614 bool ExpectCatchList = false;
615 std::unique_ptr FunctionTable;
616 if (Name == "block") {
617 push(Block);
618 ExpectBlockType = true;
619 } else if (Name == "loop") {
620 push(Loop);
621 ExpectBlockType = true;
622 } else if (Name == "try") {
623 push(Try);
624 ExpectBlockType = true;
625 } else if (Name == "if") {
626 push(If);
627 ExpectBlockType = true;
628 } else if (Name == "else") {
629 if (popAndPushWithSameSignature(Name, If, Else))
630 return true;
631 } else if (Name == "catch") {
632 if (popAndPushWithSameSignature(Name, Try, Try))
633 return true;
634 } else if (Name == "catch_all") {
635 if (popAndPushWithSameSignature(Name, Try, CatchAll))
636 return true;
637 } else if (Name == "try_table") {
638 push(TryTable);
639 ExpectBlockType = true;
640 ExpectCatchList = true;
641 } else if (Name == "end_if") {
642 if (pop(Name, If, Else))
643 return true;
644 } else if (Name == "end_try") {
645 if (pop(Name, Try, CatchAll))
646 return true;
647 } else if (Name == "end_try_table") {
648 if (pop(Name, TryTable))
649 return true;
650 } else if (Name == "delegate") {
651 if (pop(Name, Try))
652 return true;
653 } else if (Name == "end_loop") {
654 if (pop(Name, Loop))
655 return true;
656 } else if (Name == "end_block") {
657 if (pop(Name, Block))
658 return true;
659 } else if (Name == "end_function") {
660 ensureLocals(getStreamer());
661 CurrentState = EndFunction;
662 if (pop(Name, Function) || ensureEmptyNestingStack())
663 return true;
664 } else if (Name == "call_indirect" || Name == "return_call_indirect") {
665
666
667
668 if (parseFunctionTableOperand(&FunctionTable))
669 return true;
670 ExpectFuncType = true;
671 } else if (Name == "ref.test") {
672
673
674 ExpectFuncType = true;
675 }
676
677
678 auto PeekCatchList = [&]() {
680 return false;
681 AsmToken NextTok = Lexer.peekTok();
684 };
685
686
687 if (ExpectFuncType ||
688 (Lexer.is(AsmToken::LParen) && ExpectBlockType && !PeekCatchList())) {
689
690
691
692
694 auto Loc = Parser.getTok();
696 if (parseSignature(Signature))
697 return true;
698
699 TC.setLastSig(*Signature);
700 if (ExpectBlockType)
701 NestingStack.back().Sig = *Signature;
702 ExpectBlockType = false;
703
705 auto *WasmSym = static_cast<MCSymbolWasm *>(Sym);
706 WasmSym->setSignature(Signature);
708 const MCExpr *Expr =
710 Operands.push_back(std::make_unique(
711 Loc.getLoc(), Loc.getEndLoc(), WebAssemblyOperand::SymOp{Expr}));
712 }
713
714
715
716
717
718
719
720
721 if (ExpectCatchList && PeekCatchList()) {
722 if (ExpectBlockType) {
723 ExpectBlockType = false;
724 addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
725 }
726 if (parseCatchList(Operands))
727 return true;
728 ExpectCatchList = false;
729 }
730
732 auto &Tok = Lexer.getTok();
735 if (!parseSpecialFloatMaybe(false, Operands))
736 break;
737 auto &Id = Lexer.getTok();
738 if (ExpectBlockType) {
739
741 if (BT == WebAssembly::BlockType::Invalid)
742 return error("Unknown block type: ", Id);
743 addBlockTypeOperand(Operands, NameLoc, BT);
744 ExpectBlockType = false;
745 Parser.Lex();
746
747
748 if (ExpectCatchList && PeekCatchList()) {
749 if (parseCatchList(Operands))
750 return true;
751 ExpectCatchList = false;
752 }
753 } else {
754
755 const MCExpr *Val;
756 SMLoc Start = Id.getLoc();
757 SMLoc End;
758 if (Parser.parseExpression(Val, End))
759 return error("Cannot parse symbol: ", Lexer.getTok());
760 Operands.push_back(std::make_unique(
761 Start, End, WebAssemblyOperand::SymOp{Val}));
762 if (checkForP2AlignIfLoadStore(Operands, Name))
763 return true;
764 }
765 break;
766 }
768 Parser.Lex();
770 parseSingleInteger(true, Operands);
771 if (checkForP2AlignIfLoadStore(Operands, Name))
772 return true;
774 if (parseSingleFloat(true, Operands))
775 return true;
776 } else if (!parseSpecialFloatMaybe(true, Operands)) {
777 } else {
778 return error("Expected numeric constant instead got: ",
779 Lexer.getTok());
780 }
781 break;
783 parseSingleInteger(false, Operands);
784 if (checkForP2AlignIfLoadStore(Operands, Name))
785 return true;
786 break;
788 if (parseSingleFloat(false, Operands))
789 return true;
790 break;
791 }
793 Parser.Lex();
794 auto Op = std::make_unique(
795 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::BrLOp{});
797 for (;;) {
798 Op->BrL.List.push_back(Lexer.getTok().getIntVal());
801 break;
802 }
805 break;
806 }
807 default:
808 return error("Unexpected token in operand: ", Tok);
809 }
812 return true;
813 }
814 }
815
816
817
818
819
820 if (ExpectBlockType)
821 addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
822
823 if (ExpectCatchList)
824 Operands.push_back(std::make_unique(
825 NameLoc, NameLoc, WebAssemblyOperand::CaLOp{}));
826
827 if (FunctionTable)
828 Operands.push_back(std::move(FunctionTable));
829 Parser.Lex();
830 return false;
831 }
832
833 bool parseSignature(wasm::WasmSignature *Signature) {
835 return true;
836 if (parseRegTypeList(Signature->Params))
837 return true;
839 return true;
841 return true;
843 return true;
844 if (parseRegTypeList(Signature->Returns))
845 return true;
847 return true;
848 return false;
849 }
850
852 auto Op = std::make_unique(
853 Lexer.getTok().getLoc(), SMLoc(), WebAssemblyOperand::CaLOp{});
854 SMLoc EndLoc;
855
858 return true;
859
860 auto CatchStr = expectIdent();
861 if (CatchStr.empty())
862 return true;
863 uint8_t CatchOpcode =
864 StringSwitch<uint8_t>(CatchStr)
869 .Default(0xff);
870 if (CatchOpcode == 0xff)
872 "Expected catch/catch_ref/catch_all/catch_all_ref, instead got: " +
873 CatchStr);
874
875 const MCExpr *Tag = nullptr;
878 if (Parser.parseExpression(Tag))
879 return error("Cannot parse symbol: ", Lexer.getTok());
880 }
881
882 auto &DestTok = Lexer.getTok();
884 return error("Expected integer constant, instead got: ", DestTok);
885 unsigned Dest = DestTok.getIntVal();
886 Parser.Lex();
887
888 EndLoc = Lexer.getTok().getEndLoc();
890 return true;
891
892 Op->CaL.List.push_back({CatchOpcode, Tag, Dest});
893 }
894
895 Op->EndLoc = EndLoc;
897 return false;
898 }
899
900 bool checkDataSection() {
901 if (CurrentState != DataSection) {
902 auto *WS = static_cast<const MCSectionWasm *>(
903 getStreamer().getCurrentSectionOnly());
904 if (WS && WS->isText())
905 return error("data directive must occur in a data segment: ",
906 Lexer.getTok());
907 }
908 CurrentState = DataSection;
909 return false;
910 }
911
912
913
914
915 ParseStatus parseDirective(AsmToken DirectiveID) override {
917 auto &Out = getStreamer();
918 auto &TOut =
919 reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
920 auto &Ctx = Out.getContext();
921
922 if (DirectiveID.getString() == ".globaltype") {
923 auto SymName = expectIdent();
924 if (SymName.empty())
928 auto TypeTok = Lexer.getTok();
929 auto TypeName = expectIdent();
934 return error("Unknown type in .globaltype directive: ", TypeTok);
935
936
937
938 bool Mutable = true;
940 TypeTok = Lexer.getTok();
941 auto Id = expectIdent();
942 if (Id.empty())
944 if (Id == "immutable")
945 Mutable = false;
946 else
947
948 return error("Unknown type in .globaltype modifier: ", TypeTok);
949 }
950
951 auto *WasmSym =
954 WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(*Type), Mutable});
955
956 TOut.emitGlobalType(WasmSym);
958 }
959
960 if (DirectiveID.getString() == ".tabletype") {
961
962 auto SymName = expectIdent();
963 if (SymName.empty())
967
968 auto ElemTypeTok = Lexer.getTok();
969 auto ElemTypeName = expectIdent();
970 if (ElemTypeName.empty())
972 std::optionalwasm::ValType ElemType =
974 if (!ElemType)
975 return error("Unknown type in .tabletype directive: ", ElemTypeTok);
976
977 wasm::WasmLimits Limits = defaultLimits();
980
981
982
983 auto *WasmSym =
986 if (Is64) {
988 }
989 wasm::WasmTableType Type = {*ElemType, Limits};
990 WasmSym->setTableType(Type);
991 TOut.emitTableType(WasmSym);
993 }
994
995 if (DirectiveID.getString() == ".functype") {
996
997
998
999
1000
1001 auto SymName = expectIdent();
1002 if (SymName.empty())
1004 auto *WasmSym =
1006 if (WasmSym->isDefined()) {
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017 if (CurrentState != FunctionLabel) {
1018
1019 if (ensureEmptyNestingStack())
1021 push(Function);
1022 }
1023 CurrentState = FunctionStart;
1024 LastFunctionLabel = WasmSym;
1025 }
1027 if (parseSignature(Signature))
1029 if (CurrentState == FunctionStart)
1030 TC.funcDecl(*Signature);
1031 WasmSym->setSignature(Signature);
1033 TOut.emitFunctionType(WasmSym);
1034
1036 }
1037
1038 if (DirectiveID.getString() == ".export_name") {
1039 auto SymName = expectIdent();
1040 if (SymName.empty())
1044 auto ExportName = expectIdent();
1045 if (ExportName.empty())
1047 auto *WasmSym =
1049 WasmSym->setExportName(Ctx.allocateString(ExportName));
1050 TOut.emitExportName(WasmSym, ExportName);
1052 }
1053
1054 if (DirectiveID.getString() == ".import_module") {
1055 auto SymName = expectIdent();
1056 if (SymName.empty())
1060 auto ImportModule = expectIdent();
1061 if (ImportModule.empty())
1063 auto *WasmSym =
1065 WasmSym->setImportModule(Ctx.allocateString(ImportModule));
1066 TOut.emitImportModule(WasmSym, ImportModule);
1068 }
1069
1070 if (DirectiveID.getString() == ".import_name") {
1071 auto SymName = expectIdent();
1072 if (SymName.empty())
1076 auto ImportName = expectIdent();
1077 if (ImportName.empty())
1079 auto *WasmSym =
1081 WasmSym->setImportName(Ctx.allocateString(ImportName));
1082 TOut.emitImportName(WasmSym, ImportName);
1084 }
1085
1086 if (DirectiveID.getString() == ".tagtype") {
1087 auto SymName = expectIdent();
1088 if (SymName.empty())
1090 auto *WasmSym =
1093 if (parseRegTypeList(Signature->Params))
1095 WasmSym->setSignature(Signature);
1097 TOut.emitTagType(WasmSym);
1098
1100 }
1101
1102 if (DirectiveID.getString() == ".local") {
1103 if (CurrentState != FunctionStart)
1104 return error(".local directive should follow the start of a function: ",
1105 Lexer.getTok());
1107 if (parseRegTypeList(Locals))
1109 TC.localDecl(Locals);
1110 TOut.emitLocal(Locals);
1111 CurrentState = FunctionLocals;
1113 }
1114
1115 if (DirectiveID.getString() == ".int8" ||
1116 DirectiveID.getString() == ".int16" ||
1117 DirectiveID.getString() == ".int32" ||
1118 DirectiveID.getString() == ".int64") {
1119 if (checkDataSection())
1121 const MCExpr *Val;
1122 SMLoc End;
1123 if (Parser.parseExpression(Val, End))
1124 return error("Cannot parse .int expression: ", Lexer.getTok());
1125 size_t NumBits = 0;
1127 Out.emitValue(Val, NumBits / 8, End);
1129 }
1130
1131 if (DirectiveID.getString() == ".asciz") {
1132 if (checkDataSection())
1134 std::string S;
1135 if (Parser.parseEscapedString(S))
1136 return error("Cannot parse string constant: ", Lexer.getTok());
1137 Out.emitBytes(StringRef(S.c_str(), S.length() + 1));
1139 }
1140
1142 }
1143
1144
1145 void ensureLocals(MCStreamer &Out) {
1146 if (CurrentState == FunctionStart) {
1147
1148
1149
1150 auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>(
1153 CurrentState = FunctionLocals;
1154 }
1155 }
1156
1157 bool matchAndEmitInstruction(SMLoc IDLoc, unsigned & ,
1159 uint64_t &ErrorInfo,
1160 bool MatchingInlineAsm) override {
1161 MCInst Inst;
1163 FeatureBitset MissingFeatures;
1164 unsigned MatchResult = MatchInstructionImpl(
1165 Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm);
1166 switch (MatchResult) {
1167 case Match_Success: {
1168 ensureLocals(Out);
1169
1171 if (Align != -1U) {
1173 if (Op0.getImm() == -1)
1175 }
1176 if (Is64) {
1177
1178
1179
1181 static_cast<uint16_t>(Inst.getOpcode()));
1182 if (Opc64 >= 0) {
1184 }
1185 }
1186 if (!SkipTypeCheck)
1187 TC.typeCheck(IDLoc, Inst, Operands);
1189 if (CurrentState == EndFunction) {
1190 onEndOfFunction(IDLoc);
1191 } else {
1192 CurrentState = Instructions;
1193 }
1194 return false;
1195 }
1196 case Match_MissingFeature: {
1197 assert(MissingFeatures.count() > 0 && "Expected missing features");
1198 SmallString<128> Message;
1199 raw_svector_ostream OS(Message);
1200 OS << "instruction requires:";
1201 for (unsigned I = 0, E = MissingFeatures.size(); I != E; ++I)
1202 if (MissingFeatures.test(I))
1204 return Parser.Error(IDLoc, Message);
1205 }
1206 case Match_MnemonicFail:
1207 return Parser.Error(IDLoc, "invalid instruction");
1208 case Match_NearMisses:
1209 return Parser.Error(IDLoc, "ambiguous instruction");
1210 case Match_InvalidTiedOperand:
1211 case Match_InvalidOperand: {
1212 SMLoc ErrorLoc = IDLoc;
1213 if (ErrorInfo != ~0ULL) {
1214 if (ErrorInfo >= Operands.size())
1215 return Parser.Error(IDLoc, "too few operands for instruction");
1216 ErrorLoc = Operands[ErrorInfo]->getStartLoc();
1217 if (ErrorLoc == SMLoc())
1218 ErrorLoc = IDLoc;
1219 }
1220 return Parser.Error(ErrorLoc, "invalid operand for instruction");
1221 }
1222 }
1224 }
1225
1226 void doBeforeLabelEmit(MCSymbol *Symbol, SMLoc IDLoc) override {
1227
1228 auto *CWS = static_cast<const MCSectionWasm *>(
1229 getStreamer().getCurrentSectionOnly());
1230 if (!CWS->isText())
1231 return;
1232
1233 auto *WasmSym = static_cast<MCSymbolWasm *>(Symbol);
1234
1235
1237 Parser.Error(IDLoc,
1238 "Wasm doesn\'t support data symbols in text sections");
1239 return;
1240 }
1241
1242
1243
1244
1245 auto SymName = Symbol->getName();
1246 if (SymName.starts_with(".L"))
1247 return;
1248
1249
1250
1251
1252
1253 std::string SecName = (".text." + SymName).str();
1254
1255 auto *Group = CWS->getGroup();
1256
1257
1258
1259
1260 if (Group)
1261 WasmSym->setComdat(true);
1264 getStreamer().switchSection(WS);
1265
1266 if (getContext().getGenDwarfForAssembly())
1267 getContext().addGenDwarfSection(WS);
1268
1269 if (WasmSym->isFunction()) {
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279 ensureEmptyNestingStack(IDLoc);
1280 CurrentState = FunctionLabel;
1281 LastFunctionLabel = Symbol;
1282 push(Function);
1283 }
1284 }
1285
1286 void onEndOfFunction(SMLoc ErrorLoc) {
1287 if (!SkipTypeCheck)
1288 TC.endOfFunction(ErrorLoc, true);
1289
1291 }
1292
1293 void onEndOfFile() override { ensureEmptyNestingStack(); }
1294};
1295}
1296
1297
1303
1304#define GET_REGISTER_MATCHER
1305#define GET_SUBTARGET_FEATURE_NAME
1306#define GET_MATCHER_IMPLEMENTATION
1307#include "WebAssemblyGenAsmMatcher.inc"
1308
1310
1311 for (auto &ME : MatchTable0) {
1312 if (ME.Opcode == Opc) {
1313 return ME.getMnemonic();
1314 }
1315 }
1316 assert(false && "mnemonic not found");
1318}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_EXTERNAL_VISIBILITY
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static bool isReg(const MCInst &MI, unsigned OpNo)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyAsmParser()
Definition WebAssemblyAsmParser.cpp:1299
StringRef getMnemonic(unsigned Opc)
Definition WebAssemblyAsmParser.cpp:1309
static const char * getSubtargetFeatureName(uint64_t Val)
This file is part of the WebAssembly Assembler.
This file contains the declaration of the WebAssemblyMCAsmInfo class.
This file provides WebAssembly-specific target descriptions.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file registers the WebAssembly target.
This file declares WebAssembly-specific target streamer classes.
LLVM_ABI SMLoc getLoc() const
int64_t getIntVal() const
StringRef getString() const
Get the string for the current token, this includes all characters (for example, the quotes on string...
bool is(TokenKind K) const
TokenKind getKind() const
LLVM_ABI SMLoc getEndLoc() const
StringRef getIdentifier() const
Get the identifier string for the current token, which should be an identifier or a string.
constexpr bool test(unsigned I) const
constexpr size_t size() const
virtual void Initialize(MCAsmParser &Parser)
Initialize the extension for parsing using the given Parser.
Context object for machine code objects.
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
LLVM_ABI wasm::WasmSignature * createWasmSignature()
Allocates and returns a new WasmSignature instance (with empty parameter and return type lists).
StringRef allocateString(StringRef s)
Allocates a copy of the given string on the allocator managed by this context and returns the result.
LLVM_ABI MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
unsigned getOpcode() const
void addOperand(const MCOperand Op)
void setOpcode(unsigned Op)
const MCOperand & getOperand(unsigned i) const
static MCOperand createExpr(const MCExpr *Val)
static MCOperand createSFPImm(uint32_t Val)
static MCOperand createImm(int64_t Val)
static MCOperand createDFPImm(uint64_t Val)
MCParsedAsmOperand - This abstract class represents a source-level assembly instruction operand.
Wrapper class representing physical registers. Should be passed by value.
static constexpr unsigned NonUniqueID
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
MCTargetStreamer * getTargetStreamer()
bool checkFeatures(StringRef FS) const
Check whether the subtarget features are enabled/disabled as per the provided string,...
const FeatureBitset & getFeatureBits() const
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
void setFunctionTable(bool is64)
MCTargetAsmParser - Generic interface to target specific assembly parsers.
static constexpr StatusTy Failure
static constexpr StatusTy NoMatch
Represents a location in source code.
static SMLoc getFromPointer(const char *Ptr)
constexpr const char * getPointer() const
static SectionKind getText()
void push_back(const T &Elt)
StringRef - Represent a constant reference to a string, i.e.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
LLVM_ABI void clear()
Clears function-level state.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char TypeName[]
Key for Kernel::Arg::Metadata::mTypeName.
@ C
The default llvm calling convention, compatible with C.
int getWasm64Opcode(unsigned short Opcode)
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
BlockType parseBlockType(StringRef Type)
BlockType
Used as immediate MachineOperands for block signatures.
unsigned GetDefaultP2AlignAny(unsigned Opc)
Return the default p2align value for a load or store with the given opcode.
std::optional< wasm::ValType > parseType(StringRef Type)
Context & getContext() const
@ WASM_OPCODE_CATCH_ALL_REF
@ WASM_LIMITS_FLAG_HAS_MAX
@ WASM_SYMBOL_TYPE_GLOBAL
@ WASM_SYMBOL_TYPE_FUNCTION
This is an optimization pass for GlobalISel generic memory operations.
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
static bool isMem(const MachineInstr &MI, unsigned Op)
LLVM_ABI std::pair< StringRef, StringRef > getToken(StringRef Source, StringRef Delimiters=" \t\n\v\f\r")
getToken - This function extracts one token from source, ignoring any leading characters that appear ...
SmallVectorImpl< std::unique_ptr< MCParsedAsmOperand > > OperandVector
Target & getTheWebAssemblyTarget32()
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
Target & getTheWebAssemblyTarget64()
To bit_cast(const From &from) noexcept
DWARFExpression::Operation Op
@ MCSA_NoDeadStrip
.no_dead_strip (MachO)
RegisterMCAsmParser - Helper template for registering a target specific assembly parser,...
SmallVector< ValType, 1 > Returns
SmallVector< ValType, 4 > Params