diff options
Diffstat (limited to 'llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp')
| -rw-r--r-- | llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp | 225 | 
1 files changed, 23 insertions, 202 deletions
| diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 2d92b93ca70..32f34b45227 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -34,27 +34,10 @@ using namespace llvm;  namespace { -// We store register types as SimpleValueType to retain SIMD layout -// information, but must also be able to supply them as the (unnamed) -// register enum from WebAssemblyRegisterInfo.td/.inc. -static unsigned MVTToWasmReg(MVT::SimpleValueType Type) { -  switch(Type) { -    case MVT::i32: return WebAssembly::I32_0; -    case MVT::i64: return WebAssembly::I64_0; -    case MVT::f32: return WebAssembly::F32_0; -    case MVT::f64: return WebAssembly::F64_0; -    case MVT::v16i8: return WebAssembly::V128_0; -    case MVT::v8i16: return WebAssembly::V128_0; -    case MVT::v4i32: return WebAssembly::V128_0; -    case MVT::v4f32: return WebAssembly::V128_0; -    default: return MVT::INVALID_SIMPLE_VALUE_TYPE; -  } -} -  /// WebAssemblyOperand - Instances of this class represent the operands in a  /// parsed WASM machine instruction.  struct WebAssemblyOperand : public MCParsedAsmOperand { -  enum KindTy { Token, Local, Stack, Integer, Float, Symbol } Kind; +  enum KindTy { Token, Integer, Float, Symbol } Kind;    SMLoc StartLoc, EndLoc; @@ -62,19 +45,6 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {      StringRef Tok;    }; -  struct RegOp { -    // This is a (virtual) local or stack register represented as 0.. -    unsigned RegNo; -    // In most targets, the register number also encodes the type, but for -    // wasm we have to track that seperately since we have an unbounded -    // number of registers. -    // This has the unfortunate side effect that we supply a different value -    // to the table-gen matcher at different times in the process (when it -    // calls getReg() or addRegOperands(). -    // TODO: While this works, it feels brittle. and would be nice to clean up. -    MVT::SimpleValueType Type; -  }; -    struct IntOp {      int64_t Val;    }; @@ -89,7 +59,6 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {    union {      struct TokOp Tok; -    struct RegOp Reg;      struct IntOp Int;      struct FltOp Flt;      struct SymOp Sym; @@ -97,8 +66,6 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {    WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, TokOp T)      : Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {} -  WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, RegOp R) -    : Kind(K), StartLoc(Start), EndLoc(End), Reg(R) {}    WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I)      : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {}    WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F) @@ -110,14 +77,12 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {    bool isImm() const override { return Kind == Integer ||                                         Kind == Float ||                                         Kind == Symbol; } -  bool isReg() const override { return Kind == Local || Kind == Stack; }    bool isMem() const override { return false; } +  bool isReg() const override { return false; }    unsigned getReg() const override { -    assert(isReg()); -    // This is called from the tablegen matcher (MatchInstructionImpl) -    // where it expects to match the type of register, see RegOp above. -    return MVTToWasmReg(Reg.Type); +    llvm_unreachable("Assembly inspects a register operand"); +    return 0;    }    StringRef getToken() const { @@ -128,19 +93,9 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {    SMLoc getStartLoc() const override { return StartLoc; }    SMLoc getEndLoc() const override { return EndLoc; } -  void addRegOperands(MCInst &Inst, unsigned N) const { -    assert(N == 1 && "Invalid number of operands!"); -    assert(isReg() && "Not a register operand!"); -    // This is called from the tablegen matcher (MatchInstructionImpl) -    // where it expects to output the actual register index, see RegOp above. -    unsigned R = Reg.RegNo; -    if (Kind == Stack) { -      // A stack register is represented as a large negative number. -      // See WebAssemblyRegNumbering::runOnMachineFunction and -      // getWARegStackId for why this | is needed. -      R |= INT32_MIN; -    } -    Inst.addOperand(MCOperand::createReg(R)); +  void addRegOperands(MCInst &, unsigned) const { +    // Required by the assembly matcher. +    llvm_unreachable("Assembly matcher creates register operands");    }    void addImmOperands(MCInst &Inst, unsigned N) const { @@ -160,12 +115,6 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {      case Token:        OS << "Tok:" << Tok.Tok;        break; -    case Local: -      OS << "Loc:" << Reg.RegNo << ":" << static_cast<int>(Reg.Type); -      break; -    case Stack: -      OS << "Stk:" << Reg.RegNo << ":" << static_cast<int>(Reg.Type); -      break;      case Integer:        OS << "Int:" << Int.Val;        break; @@ -182,11 +131,6 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {  class WebAssemblyAsmParser final : public MCTargetAsmParser {    MCAsmParser &Parser;    MCAsmLexer &Lexer; -  // These are for the current function being parsed: -  // These are vectors since register assignments are so far non-sparse. -  // Replace by map if necessary. -  std::vector<MVT::SimpleValueType> LocalTypes; -  std::vector<MVT::SimpleValueType> StackTypes;    MCSymbol *LastLabel;  public: @@ -236,68 +180,6 @@ public:          .Default(MVT::INVALID_SIMPLE_VALUE_TYPE);    } -  MVT::SimpleValueType &GetType( -      std::vector<MVT::SimpleValueType> &Types, size_t i) { -    Types.resize(std::max(i + 1, Types.size()), MVT::INVALID_SIMPLE_VALUE_TYPE); -    return Types[i]; -  } - -  bool ParseReg(OperandVector &Operands, StringRef TypePrefix) { -    if (Lexer.is(AsmToken::Integer)) { -      auto &Local = Lexer.getTok(); -      // This is a reference to a local, turn it into a virtual register. -      auto LocalNo = static_cast<unsigned>(Local.getIntVal()); -      Operands.push_back(make_unique<WebAssemblyOperand>( -                           WebAssemblyOperand::Local, Local.getLoc(), -                           Local.getEndLoc(), -                           WebAssemblyOperand::RegOp{LocalNo, -                               GetType(LocalTypes, LocalNo)})); -      Parser.Lex(); -    } else if (Lexer.is(AsmToken::Identifier)) { -      auto &StackRegTok = Lexer.getTok(); -      // These are push/pop/drop pseudo stack registers, which we turn -      // into virtual registers also. The stackify pass will later turn them -      // back into implicit stack references if possible. -      auto StackReg = StackRegTok.getString(); -      auto StackOp = StackReg.take_while([](char c) { return isalpha(c); }); -      auto Reg = StackReg.drop_front(StackOp.size()); -      unsigned long long ParsedRegNo = 0; -      if (!Reg.empty() && getAsUnsignedInteger(Reg, 10, ParsedRegNo)) -        return Error("Cannot parse stack register index: ", StackRegTok); -      unsigned RegNo = static_cast<unsigned>(ParsedRegNo); -      if (StackOp == "push") { -        // This defines a result, record register type. -        auto RegType = ParseRegType(TypePrefix); -        GetType(StackTypes, RegNo) = RegType; -        Operands.push_back(make_unique<WebAssemblyOperand>( -                             WebAssemblyOperand::Stack, -                             StackRegTok.getLoc(), -                             StackRegTok.getEndLoc(), -                             WebAssemblyOperand::RegOp{RegNo, RegType})); -      } else if (StackOp == "pop") { -        // This uses a previously defined stack value. -        auto RegType = GetType(StackTypes, RegNo); -        Operands.push_back(make_unique<WebAssemblyOperand>( -                             WebAssemblyOperand::Stack, -                             StackRegTok.getLoc(), -                             StackRegTok.getEndLoc(), -                             WebAssemblyOperand::RegOp{RegNo, RegType})); -      } else if (StackOp == "drop") { -        // This operand will be dropped, since it is part of an instruction -        // whose result is void. -      } else { -        return Error("Unknown stack register prefix: ", StackRegTok); -      } -      Parser.Lex(); -    } else { -      return Error( -            "Expected identifier/integer following $, instead got: ", -            Lexer.getTok()); -    } -    IsNext(AsmToken::Equal); -    return false; -  } -    void ParseSingleInteger(bool IsNegative, OperandVector &Operands) {      auto &Int = Lexer.getTok();      int64_t Val = Int.getIntVal(); @@ -310,36 +192,26 @@ public:    bool ParseOperandStartingWithInteger(bool IsNegative,                                         OperandVector &Operands, -                                       StringRef InstType) { +                                       StringRef InstName) {      ParseSingleInteger(IsNegative, Operands); -    if (Lexer.is(AsmToken::LParen)) { -      // Parse load/store operands of the form: offset($reg)align -      auto &LParen = Lexer.getTok(); -      Operands.push_back( -            make_unique<WebAssemblyOperand>(WebAssemblyOperand::Token, -                                            LParen.getLoc(), -                                            LParen.getEndLoc(), -                                            WebAssemblyOperand::TokOp{ -                                              LParen.getString()})); -      Parser.Lex(); -      if (Expect(AsmToken::Dollar, "register")) return true; -      if (ParseReg(Operands, InstType)) return true; -      auto &RParen = Lexer.getTok(); -      Operands.push_back( -            make_unique<WebAssemblyOperand>(WebAssemblyOperand::Token, -                                            RParen.getLoc(), -                                            RParen.getEndLoc(), -                                            WebAssemblyOperand::TokOp{ -                                              RParen.getString()})); -      if (Expect(AsmToken::RParen, ")")) return true; -      if (Lexer.is(AsmToken::Integer)) { +    // FIXME: there is probably a cleaner way to do this. +    auto IsLoadStore = InstName.startswith("load") || +                       InstName.startswith("store") || +                       InstName.startswith("atomic_load") || +                       InstName.startswith("atomic_store"); +    if (IsLoadStore) { +      // Parse load/store operands of the form: offset align +      auto &Offset = Lexer.getTok(); +      if (Offset.is(AsmToken::Integer)) {          ParseSingleInteger(false, Operands);        } else {          // Alignment not specified.          // FIXME: correctly derive a default from the instruction. +        // We can't just call WebAssembly::GetDefaultP2Align since we don't have +        // an opcode until after the assembly matcher.          Operands.push_back(make_unique<WebAssemblyOperand>( -                             WebAssemblyOperand::Integer, RParen.getLoc(), -                             RParen.getEndLoc(), WebAssemblyOperand::IntOp{0})); +                             WebAssemblyOperand::Integer, Offset.getLoc(), +                             Offset.getEndLoc(), WebAssemblyOperand::IntOp{0}));        }      }      return false; @@ -360,11 +232,6 @@ public:      while (Lexer.isNot(AsmToken::EndOfStatement)) {        auto &Tok = Lexer.getTok();        switch (Tok.getKind()) { -      case AsmToken::Dollar: { -        Parser.Lex(); -        if (ParseReg(Operands, NamePair.first)) return true; -        break; -      }        case AsmToken::Identifier: {          auto &Id = Lexer.getTok();          const MCExpr *Val; @@ -380,11 +247,11 @@ public:          Parser.Lex();          if (Lexer.isNot(AsmToken::Integer))            return Error("Expected integer instead got: ", Lexer.getTok()); -        if (ParseOperandStartingWithInteger(true, Operands, NamePair.first)) +        if (ParseOperandStartingWithInteger(true, Operands, NamePair.second))            return true;          break;        case AsmToken::Integer: -        if (ParseOperandStartingWithInteger(false, Operands, NamePair.first)) +        if (ParseOperandStartingWithInteger(false, Operands, NamePair.second))            return true;          break;        case AsmToken::Real: { @@ -405,35 +272,6 @@ public:        }      }      Parser.Lex(); -    // Call instructions are vararg, but the tablegen matcher doesn't seem to -    // support that, so for now we strip these extra operands. -    // This is problematic if these arguments are not simple $pop stack -    // registers, since e.g. a local register would get lost, so we check for -    // this. This can be the case when using -disable-wasm-explicit-locals -    // which currently s2wasm requires. -    // TODO: Instead, we can move this code to MatchAndEmitInstruction below and -    // actually generate get_local instructions on the fly. -    // Or even better, improve the matcher to support vararg? -    auto IsIndirect = NamePair.second == "call_indirect"; -    if (IsIndirect || NamePair.second == "call") { -      // Figure out number of fixed operands from the instruction. -      size_t CallOperands = 1;  // The name token. -      if (!IsIndirect) CallOperands++;  // The function index. -      if (!NamePair.first.empty()) CallOperands++;  // The result register. -      if (Operands.size() > CallOperands) { -        // Ensure operands we drop are all $pop. -        for (size_t I = CallOperands; I < Operands.size(); I++) { -          auto Operand = -              reinterpret_cast<WebAssemblyOperand *>(Operands[I].get()); -          if (Operand->Kind != WebAssemblyOperand::Stack) -            Parser.Error(NameLoc, -              "Call instruction has non-stack arguments, if this code was " -              "generated with -disable-wasm-explicit-locals please remove it"); -        } -        // Drop unneeded operands. -        Operands.resize(CallOperands); -      } -    }      // Block instructions require a signature index, but these are missing in      // assembly, so we add a dummy one explicitly (since we have no control      // over signature tables here, we assume these will be regenerated when @@ -443,17 +281,6 @@ public:                             WebAssemblyOperand::Integer, NameLoc,                             NameLoc, WebAssemblyOperand::IntOp{-1}));      } -    // These don't specify the type, which has to derived from the local index. -    if (NamePair.second == "get_local" || NamePair.second == "tee_local") { -      if (Operands.size() >= 3 && Operands[1]->isReg() && -          Operands[2]->isImm()) { -        auto Op1 = reinterpret_cast<WebAssemblyOperand *>(Operands[1].get()); -        auto Op2 = reinterpret_cast<WebAssemblyOperand *>(Operands[2].get()); -        auto Type = GetType(LocalTypes, static_cast<size_t>(Op2->Int.Val)); -        Op1->Reg.Type = Type; -        GetType(StackTypes, Op1->Reg.RegNo) = Type; -      } -    }      return false;    } @@ -477,11 +304,6 @@ public:              IsNext(AsmToken::At) &&              Lexer.is(AsmToken::Identifier)))          return Error("Expected label,@type declaration, got: ", Lexer.getTok()); -      if (Lexer.getTok().getString() == "function") { -        // Track locals from start of function. -        LocalTypes.clear(); -        StackTypes.clear(); -      }        Parser.Lex();        //Out.EmitSymbolAttribute(??, MCSA_ELF_TypeFunction);      } else if (DirectiveID.getString() == ".param" || @@ -494,7 +316,6 @@ public:        while (Lexer.is(AsmToken::Identifier)) {          auto RegType = ParseRegType(Lexer.getTok().getString());          if (RegType == MVT::INVALID_SIMPLE_VALUE_TYPE) return true; -        LocalTypes.push_back(RegType);          if (DirectiveID.getString() == ".param") {            Params.push_back(RegType);          } else { | 

