LCOV - code coverage report
Current view: top level - lib/Target/WebAssembly/AsmParser - WebAssemblyAsmParser.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 99 181 54.7 %
Date: 2018-10-20 13:21:21 Functions: 9 24 37.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //==- WebAssemblyAsmParser.cpp - Assembler for WebAssembly -*- C++ -*-==//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : ///
      10             : /// \file
      11             : /// This file is part of the WebAssembly Assembler.
      12             : ///
      13             : /// It contains code to translate a parsed .s file into MCInsts.
      14             : ///
      15             : //===----------------------------------------------------------------------===//
      16             : 
      17             : #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
      18             : #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
      19             : #include "WebAssembly.h"
      20             : #include "llvm/MC/MCContext.h"
      21             : #include "llvm/MC/MCInst.h"
      22             : #include "llvm/MC/MCInstrInfo.h"
      23             : #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
      24             : #include "llvm/MC/MCParser/MCTargetAsmParser.h"
      25             : #include "llvm/MC/MCStreamer.h"
      26             : #include "llvm/MC/MCSubtargetInfo.h"
      27             : #include "llvm/MC/MCSymbol.h"
      28             : #include "llvm/Support/Endian.h"
      29             : #include "llvm/Support/TargetRegistry.h"
      30             : 
      31             : using namespace llvm;
      32             : 
      33             : #define DEBUG_TYPE "wasm-asm-parser"
      34             : 
      35             : namespace {
      36             : 
      37             : /// WebAssemblyOperand - Instances of this class represent the operands in a
      38             : /// parsed WASM machine instruction.
      39             : struct WebAssemblyOperand : public MCParsedAsmOperand {
      40             :   enum KindTy { Token, Integer, Float, Symbol } Kind;
      41             : 
      42             :   SMLoc StartLoc, EndLoc;
      43             : 
      44             :   struct TokOp {
      45             :     StringRef Tok;
      46             :   };
      47             : 
      48             :   struct IntOp {
      49             :     int64_t Val;
      50             :   };
      51             : 
      52             :   struct FltOp {
      53             :     double Val;
      54             :   };
      55             : 
      56             :   struct SymOp {
      57             :     const MCExpr *Exp;
      58             :   };
      59             : 
      60             :   union {
      61             :     struct TokOp Tok;
      62             :     struct IntOp Int;
      63             :     struct FltOp Flt;
      64             :     struct SymOp Sym;
      65             :   };
      66             : 
      67             :   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, TokOp T)
      68           0 :       : Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {}
      69             :   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I)
      70         204 :       : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {}
      71             :   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F)
      72          14 :       : Kind(K), StartLoc(Start), EndLoc(End), Flt(F) {}
      73             :   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, SymOp S)
      74           6 :       : Kind(K), StartLoc(Start), EndLoc(End), Sym(S) {}
      75             : 
      76         189 :   bool isToken() const override { return Kind == Token; }
      77           0 :   bool isImm() const override {
      78         189 :     return Kind == Integer || Kind == Float || Kind == Symbol;
      79             :   }
      80           0 :   bool isMem() const override { return false; }
      81           0 :   bool isReg() const override { return false; }
      82             : 
      83           0 :   unsigned getReg() const override {
      84           0 :     llvm_unreachable("Assembly inspects a register operand");
      85             :     return 0;
      86             :   }
      87             : 
      88           0 :   StringRef getToken() const {
      89             :     assert(isToken());
      90           0 :     return Tok.Tok;
      91             :   }
      92             : 
      93           0 :   SMLoc getStartLoc() const override { return StartLoc; }
      94           0 :   SMLoc getEndLoc() const override { return EndLoc; }
      95             : 
      96           0 :   void addRegOperands(MCInst &, unsigned) const {
      97             :     // Required by the assembly matcher.
      98           0 :     llvm_unreachable("Assembly matcher creates register operands");
      99             :   }
     100             : 
     101           0 :   void addImmOperands(MCInst &Inst, unsigned N) const {
     102             :     assert(N == 1 && "Invalid number of operands!");
     103           0 :     if (Kind == Integer)
     104           0 :       Inst.addOperand(MCOperand::createImm(Int.Val));
     105           0 :     else if (Kind == Float)
     106           0 :       Inst.addOperand(MCOperand::createFPImm(Flt.Val));
     107           0 :     else if (Kind == Symbol)
     108           0 :       Inst.addOperand(MCOperand::createExpr(Sym.Exp));
     109             :     else
     110           0 :       llvm_unreachable("Should be immediate or symbol!");
     111           0 :   }
     112             : 
     113           0 :   void print(raw_ostream &OS) const override {
     114           0 :     switch (Kind) {
     115           0 :     case Token:
     116           0 :       OS << "Tok:" << Tok.Tok;
     117           0 :       break;
     118           0 :     case Integer:
     119           0 :       OS << "Int:" << Int.Val;
     120           0 :       break;
     121           0 :     case Float:
     122           0 :       OS << "Flt:" << Flt.Val;
     123           0 :       break;
     124           0 :     case Symbol:
     125           0 :       OS << "Sym:" << Sym.Exp;
     126           0 :       break;
     127             :     }
     128           0 :   }
     129             : };
     130             : 
     131             : class WebAssemblyAsmParser final : public MCTargetAsmParser {
     132             :   MCAsmParser &Parser;
     133             :   MCAsmLexer &Lexer;
     134             :   MCSymbol *LastLabel;
     135             : 
     136             : public:
     137           2 :   WebAssemblyAsmParser(const MCSubtargetInfo &sti, MCAsmParser &Parser,
     138             :                        const MCInstrInfo &mii, const MCTargetOptions &Options)
     139           2 :       : MCTargetAsmParser(Options, sti, mii), Parser(Parser),
     140           2 :         Lexer(Parser.getLexer()), LastLabel(nullptr) {
     141           2 :     setAvailableFeatures(ComputeAvailableFeatures(sti.getFeatureBits()));
     142           2 :   }
     143             : 
     144             : #define GET_ASSEMBLER_HEADER
     145             : #include "WebAssemblyGenAsmMatcher.inc"
     146             : 
     147             :   // TODO: This is required to be implemented, but appears unused.
     148           0 :   bool ParseRegister(unsigned & /*RegNo*/, SMLoc & /*StartLoc*/,
     149             :                      SMLoc & /*EndLoc*/) override {
     150           0 :     llvm_unreachable("ParseRegister is not implemented.");
     151             :   }
     152             : 
     153           0 :   bool Error(const StringRef &msg, const AsmToken &tok) {
     154           0 :     return Parser.Error(tok.getLoc(), msg + tok.getString());
     155             :   }
     156             : 
     157           0 :   bool IsNext(AsmToken::TokenKind Kind) {
     158           0 :     auto ok = Lexer.is(Kind);
     159          76 :     if (ok)
     160          74 :       Parser.Lex();
     161           0 :     return ok;
     162             :   }
     163             : 
     164          67 :   bool Expect(AsmToken::TokenKind Kind, const char *KindName) {
     165         134 :     if (!IsNext(Kind))
     166           0 :       return Error(std::string("Expected ") + KindName + ", instead got: ",
     167           0 :                    Lexer.getTok());
     168             :     return false;
     169             :   }
     170             : 
     171           0 :   MVT::SimpleValueType ParseRegType(const StringRef &RegType) {
     172             :     // Derive type from .param .local decls, or the instruction itself.
     173           0 :     return StringSwitch<MVT::SimpleValueType>(RegType)
     174           0 :         .Case("i32", MVT::i32)
     175           0 :         .Case("i64", MVT::i64)
     176           0 :         .Case("f32", MVT::f32)
     177           0 :         .Case("f64", MVT::f64)
     178           0 :         .Case("i8x16", MVT::v16i8)
     179           0 :         .Case("i16x8", MVT::v8i16)
     180           0 :         .Case("i32x4", MVT::v4i32)
     181           0 :         .Case("i64x2", MVT::v2i64)
     182           0 :         .Case("f32x4", MVT::v4f32)
     183           0 :         .Case("f64x2", MVT::v2f64)
     184             :         // arbitrarily chosen vector type to associate with "v128"
     185             :         // FIXME: should these be EVTs to avoid this arbitrary hack? Do we want
     186             :         // to accept more specific SIMD register types?
     187           0 :         .Case("v128", MVT::v16i8)
     188           0 :         .Default(MVT::INVALID_SIMPLE_VALUE_TYPE);
     189             :   }
     190             : 
     191          97 :   void ParseSingleInteger(bool IsNegative, OperandVector &Operands) {
     192          97 :     auto &Int = Lexer.getTok();
     193             :     int64_t Val = Int.getIntVal();
     194          97 :     if (IsNegative)
     195           1 :       Val = -Val;
     196          97 :     Operands.push_back(make_unique<WebAssemblyOperand>(
     197          97 :         WebAssemblyOperand::Integer, Int.getLoc(), Int.getEndLoc(),
     198             :         WebAssemblyOperand::IntOp{Val}));
     199          97 :     Parser.Lex();
     200          97 :   }
     201             : 
     202          97 :   bool ParseOperandStartingWithInteger(bool IsNegative, OperandVector &Operands,
     203             :                                        StringRef InstName) {
     204          97 :     ParseSingleInteger(IsNegative, Operands);
     205             :     // FIXME: there is probably a cleaner way to do this.
     206             :     auto IsLoadStore = InstName.startswith("load") ||
     207             :                        InstName.startswith("store") ||
     208             :                        InstName.startswith("atomic_load") ||
     209             :                        InstName.startswith("atomic_store");
     210             :     if (IsLoadStore) {
     211             :       // Parse load/store operands of the form: offset align
     212           3 :       auto &Offset = Lexer.getTok();
     213           3 :       if (Offset.is(AsmToken::Integer)) {
     214           0 :         ParseSingleInteger(false, Operands);
     215             :       } else {
     216             :         // Alignment not specified.
     217             :         // FIXME: correctly derive a default from the instruction.
     218             :         // We can't just call WebAssembly::GetDefaultP2Align since we don't have
     219             :         // an opcode until after the assembly matcher.
     220           3 :         Operands.push_back(make_unique<WebAssemblyOperand>(
     221           6 :             WebAssemblyOperand::Integer, Offset.getLoc(), Offset.getEndLoc(),
     222             :             WebAssemblyOperand::IntOp{0}));
     223             :       }
     224             :     }
     225          97 :     return false;
     226             :   }
     227             : 
     228         177 :   bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
     229             :                         SMLoc NameLoc, OperandVector &Operands) override {
     230             :     // Note: Name does NOT point into the sourcecode, but to a local, so
     231             :     // use NameLoc instead.
     232         177 :     Name = StringRef(NameLoc.getPointer(), Name.size());
     233             :     // WebAssembly has instructions with / in them, which AsmLexer parses
     234             :     // as seperate tokens, so if we find such tokens immediately adjacent (no
     235             :     // whitespace), expand the name to include them:
     236             :     for (;;) {
     237         186 :       auto &Sep = Lexer.getTok();
     238         186 :       if (Sep.getLoc().getPointer() != Name.end() ||
     239         140 :           Sep.getKind() != AsmToken::Slash) break;
     240             :       // Extend name with /
     241           9 :       Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());
     242           9 :       Parser.Lex();
     243             :       // We must now find another identifier, or error.
     244           9 :       auto &Id = Lexer.getTok();
     245          18 :       if (Id.getKind() != AsmToken::Identifier ||
     246           9 :           Id.getLoc().getPointer() != Name.end())
     247           0 :         return Error("Incomplete instruction name: ", Id);
     248           9 :       Name = StringRef(Name.begin(), Name.size() + Id.getString().size());
     249           9 :       Parser.Lex();
     250           9 :     }
     251             :     // Now construct the name as first operand.
     252         354 :     Operands.push_back(make_unique<WebAssemblyOperand>(
     253         354 :         WebAssemblyOperand::Token, NameLoc, SMLoc::getFromPointer(Name.end()),
     254         354 :         WebAssemblyOperand::TokOp{Name}));
     255         177 :     auto NamePair = Name.split('.');
     256             :     // If no '.', there is no type prefix.
     257         335 :     auto BaseName = NamePair.second.empty() ? NamePair.first : NamePair.second;
     258         568 :     while (Lexer.isNot(AsmToken::EndOfStatement)) {
     259             :       auto &Tok = Lexer.getTok();
     260         107 :       switch (Tok.getKind()) {
     261           3 :       case AsmToken::Identifier: {
     262             :         auto &Id = Lexer.getTok();
     263             :         const MCExpr *Val;
     264           3 :         SMLoc End;
     265           3 :         if (Parser.parsePrimaryExpr(Val, End))
     266           0 :           return Error("Cannot parse symbol: ", Lexer.getTok());
     267           3 :         Operands.push_back(make_unique<WebAssemblyOperand>(
     268           3 :             WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(),
     269           3 :             WebAssemblyOperand::SymOp{Val}));
     270           3 :         break;
     271             :       }
     272           1 :       case AsmToken::Minus:
     273           1 :         Parser.Lex();
     274           2 :         if (Lexer.isNot(AsmToken::Integer))
     275           0 :           return Error("Expected integer instead got: ", Lexer.getTok());
     276           1 :         if (ParseOperandStartingWithInteger(true, Operands, BaseName))
     277             :           return true;
     278             :         break;
     279          96 :       case AsmToken::Integer:
     280          96 :         if (ParseOperandStartingWithInteger(false, Operands, BaseName))
     281             :           return true;
     282             :         break;
     283           7 :       case AsmToken::Real: {
     284             :         double Val;
     285           7 :         if (Tok.getString().getAsDouble(Val, false))
     286           0 :           return Error("Cannot parse real: ", Tok);
     287           7 :         Operands.push_back(make_unique<WebAssemblyOperand>(
     288           7 :             WebAssemblyOperand::Float, Tok.getLoc(), Tok.getEndLoc(),
     289           7 :             WebAssemblyOperand::FltOp{Val}));
     290           7 :         Parser.Lex();
     291           7 :         break;
     292             :       }
     293             :       default:
     294           0 :         return Error("Unexpected token in operand: ", Tok);
     295             :       }
     296         214 :       if (Lexer.isNot(AsmToken::EndOfStatement)) {
     297          63 :         if (Expect(AsmToken::Comma, ","))
     298             :           return true;
     299             :       }
     300             :     }
     301         177 :     Parser.Lex();
     302             :     // Block instructions require a signature index, but these are missing in
     303             :     // assembly, so we add a dummy one explicitly (since we have no control
     304             :     // over signature tables here, we assume these will be regenerated when
     305             :     // the wasm module is generated).
     306             :     if (BaseName == "block" || BaseName == "loop") {
     307           4 :       Operands.push_back(make_unique<WebAssemblyOperand>(
     308             :           WebAssemblyOperand::Integer, NameLoc, NameLoc,
     309             :           WebAssemblyOperand::IntOp{-1}));
     310             :     }
     311             :     return false;
     312             :   }
     313             : 
     314           3 :   void onLabelParsed(MCSymbol *Symbol) override { LastLabel = Symbol; }
     315             : 
     316           4 :   bool ParseDirective(AsmToken DirectiveID) override {
     317             :     assert(DirectiveID.getKind() == AsmToken::Identifier);
     318             :     auto &Out = getStreamer();
     319             :     auto &TOut =
     320             :         reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
     321             :     // TODO: we're just parsing the subset of directives we're interested in,
     322             :     // and ignoring ones we don't recognise. We should ideally verify
     323             :     // all directives here.
     324             :     if (DirectiveID.getString() == ".type") {
     325             :       // This could be the start of a function, check if followed by
     326             :       // "label,@function"
     327           4 :       if (!(IsNext(AsmToken::Identifier) && IsNext(AsmToken::Comma) &&
     328           2 :             IsNext(AsmToken::At) && Lexer.is(AsmToken::Identifier)))
     329           0 :         return Error("Expected label,@type declaration, got: ", Lexer.getTok());
     330           1 :       Parser.Lex();
     331             :       // Out.EmitSymbolAttribute(??, MCSA_ELF_TypeFunction);
     332             :     } else if (DirectiveID.getString() == ".param" ||
     333             :                DirectiveID.getString() == ".local") {
     334             :       // Track the number of locals, needed for correct virtual register
     335             :       // assignment elsewhere.
     336             :       // Also output a directive to the streamer.
     337             :       std::vector<MVT> Params;
     338             :       std::vector<MVT> Locals;
     339          12 :       while (Lexer.is(AsmToken::Identifier)) {
     340           6 :         auto RegType = ParseRegType(Lexer.getTok().getString());
     341           6 :         if (RegType == MVT::INVALID_SIMPLE_VALUE_TYPE)
     342             :           return true;
     343             :         if (DirectiveID.getString() == ".param") {
     344           2 :           Params.push_back(RegType);
     345             :         } else {
     346           4 :           Locals.push_back(RegType);
     347             :         }
     348           6 :         Parser.Lex();
     349          10 :         if (!IsNext(AsmToken::Comma))
     350             :           break;
     351             :       }
     352             :       assert(LastLabel);
     353           4 :       TOut.emitParam(LastLabel, Params);
     354           4 :       TOut.emitLocal(Locals);
     355             :     } else {
     356             :       // For now, ignore anydirective we don't recognize:
     357           2 :       while (Lexer.isNot(AsmToken::EndOfStatement))
     358           0 :         Parser.Lex();
     359             :     }
     360           4 :     return Expect(AsmToken::EndOfStatement, "EOL");
     361             :   }
     362             : 
     363         177 :   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
     364             :                                OperandVector &Operands, MCStreamer &Out,
     365             :                                uint64_t &ErrorInfo,
     366             :                                bool MatchingInlineAsm) override {
     367             :     MCInst Inst;
     368             :     unsigned MatchResult =
     369         177 :         MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
     370         177 :     switch (MatchResult) {
     371         177 :     case Match_Success: {
     372         177 :       Out.EmitInstruction(Inst, getSTI());
     373         177 :       return false;
     374             :     }
     375           0 :     case Match_MissingFeature:
     376           0 :       return Parser.Error(
     377             :           IDLoc, "instruction requires a WASM feature not currently enabled");
     378           0 :     case Match_MnemonicFail:
     379           0 :       return Parser.Error(IDLoc, "invalid instruction");
     380           0 :     case Match_NearMisses:
     381           0 :       return Parser.Error(IDLoc, "ambiguous instruction");
     382           0 :     case Match_InvalidTiedOperand:
     383             :     case Match_InvalidOperand: {
     384           0 :       SMLoc ErrorLoc = IDLoc;
     385           0 :       if (ErrorInfo != ~0ULL) {
     386           0 :         if (ErrorInfo >= Operands.size())
     387           0 :           return Parser.Error(IDLoc, "too few operands for instruction");
     388           0 :         ErrorLoc = Operands[ErrorInfo]->getStartLoc();
     389           0 :         if (ErrorLoc == SMLoc())
     390             :           ErrorLoc = IDLoc;
     391             :       }
     392           0 :       return Parser.Error(ErrorLoc, "invalid operand for instruction");
     393             :     }
     394             :     }
     395           0 :     llvm_unreachable("Implement any new match types added!");
     396             :   }
     397             : };
     398             : } // end anonymous namespace
     399             : 
     400             : // Force static initialization.
     401       75416 : extern "C" void LLVMInitializeWebAssemblyAsmParser() {
     402       75416 :   RegisterMCAsmParser<WebAssemblyAsmParser> X(getTheWebAssemblyTarget32());
     403       75416 :   RegisterMCAsmParser<WebAssemblyAsmParser> Y(getTheWebAssemblyTarget64());
     404       75416 : }
     405             : 
     406             : #define GET_REGISTER_MATCHER
     407             : #define GET_MATCHER_IMPLEMENTATION
     408             : #include "WebAssemblyGenAsmMatcher.inc"

Generated by: LCOV version 1.13