diff options
Diffstat (limited to 'lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp')
-rw-r--r-- | lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp | 100 |
1 files changed, 68 insertions, 32 deletions
diff --git a/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 09628e872dd5..53a96fd6a97d 100644 --- a/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -313,16 +313,17 @@ public: return Optional<wasm::ValType>(); } - WebAssembly::ExprType parseBlockType(StringRef ID) { - return StringSwitch<WebAssembly::ExprType>(ID) - .Case("i32", WebAssembly::ExprType::I32) - .Case("i64", WebAssembly::ExprType::I64) - .Case("f32", WebAssembly::ExprType::F32) - .Case("f64", WebAssembly::ExprType::F64) - .Case("v128", WebAssembly::ExprType::V128) - .Case("exnref", WebAssembly::ExprType::Exnref) - .Case("void", WebAssembly::ExprType::Void) - .Default(WebAssembly::ExprType::Invalid); + WebAssembly::BlockType parseBlockType(StringRef ID) { + // Multivalue block types are handled separately in parseSignature + return StringSwitch<WebAssembly::BlockType>(ID) + .Case("i32", WebAssembly::BlockType::I32) + .Case("i64", WebAssembly::BlockType::I64) + .Case("f32", WebAssembly::BlockType::F32) + .Case("f64", WebAssembly::BlockType::F64) + .Case("v128", WebAssembly::BlockType::V128) + .Case("exnref", WebAssembly::BlockType::Exnref) + .Case("void", WebAssembly::BlockType::Void) + .Default(WebAssembly::BlockType::Invalid); } bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) { @@ -343,7 +344,7 @@ public: int64_t Val = Int.getIntVal(); if (IsNegative) Val = -Val; - Operands.push_back(make_unique<WebAssemblyOperand>( + Operands.push_back(std::make_unique<WebAssemblyOperand>( WebAssemblyOperand::Integer, Int.getLoc(), Int.getEndLoc(), WebAssemblyOperand::IntOp{Val})); Parser.Lex(); @@ -356,7 +357,7 @@ public: return error("Cannot parse real: ", Flt); if (IsNegative) Val = -Val; - Operands.push_back(make_unique<WebAssemblyOperand>( + Operands.push_back(std::make_unique<WebAssemblyOperand>( WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val})); Parser.Lex(); @@ -378,7 +379,7 @@ public: } if (IsNegative) Val = -Val; - Operands.push_back(make_unique<WebAssemblyOperand>( + Operands.push_back(std::make_unique<WebAssemblyOperand>( WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val})); Parser.Lex(); @@ -407,7 +408,7 @@ public: // an opcode until after the assembly matcher, so set a default to fix // up later. auto Tok = Lexer.getTok(); - Operands.push_back(make_unique<WebAssemblyOperand>( + Operands.push_back(std::make_unique<WebAssemblyOperand>( WebAssemblyOperand::Integer, Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1})); } @@ -416,8 +417,8 @@ public: } void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc, - WebAssembly::ExprType BT) { - Operands.push_back(make_unique<WebAssemblyOperand>( + WebAssembly::BlockType BT) { + Operands.push_back(std::make_unique<WebAssemblyOperand>( WebAssemblyOperand::Integer, NameLoc, NameLoc, WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)})); } @@ -449,13 +450,14 @@ public: } // Now construct the name as first operand. - Operands.push_back(make_unique<WebAssemblyOperand>( + Operands.push_back(std::make_unique<WebAssemblyOperand>( WebAssemblyOperand::Token, NameLoc, SMLoc::getFromPointer(Name.end()), WebAssemblyOperand::TokOp{Name})); // If this instruction is part of a control flow structure, ensure // proper nesting. bool ExpectBlockType = false; + bool ExpectFuncType = false; if (Name == "block") { push(Block); ExpectBlockType = true; @@ -489,9 +491,37 @@ public: if (pop(Name, Block)) return true; } else if (Name == "end_function") { + ensureLocals(getStreamer()); CurrentState = EndFunction; if (pop(Name, Function) || ensureEmptyNestingStack()) return true; + } else if (Name == "call_indirect" || Name == "return_call_indirect") { + ExpectFuncType = true; + } + + if (ExpectFuncType || (ExpectBlockType && Lexer.is(AsmToken::LParen))) { + // This has a special TYPEINDEX operand which in text we + // represent as a signature, such that we can re-build this signature, + // attach it to an anonymous symbol, which is what WasmObjectWriter + // expects to be able to recreate the actual unique-ified type indices. + auto Loc = Parser.getTok(); + auto Signature = std::make_unique<wasm::WasmSignature>(); + if (parseSignature(Signature.get())) + return true; + // Got signature as block type, don't need more + ExpectBlockType = false; + auto &Ctx = getStreamer().getContext(); + // The "true" here will cause this to be a nameless symbol. + MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true); + auto *WasmSym = cast<MCSymbolWasm>(Sym); + WasmSym->setSignature(Signature.get()); + addSignature(std::move(Signature)); + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + const MCExpr *Expr = MCSymbolRefExpr::create( + WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx); + Operands.push_back(std::make_unique<WebAssemblyOperand>( + WebAssemblyOperand::Symbol, Loc.getLoc(), Loc.getEndLoc(), + WebAssemblyOperand::SymOp{Expr})); } while (Lexer.isNot(AsmToken::EndOfStatement)) { @@ -504,7 +534,7 @@ public: if (ExpectBlockType) { // Assume this identifier is a block_type. auto BT = parseBlockType(Id.getString()); - if (BT == WebAssembly::ExprType::Invalid) + if (BT == WebAssembly::BlockType::Invalid) return error("Unknown block type: ", Id); addBlockTypeOperand(Operands, NameLoc, BT); Parser.Lex(); @@ -514,7 +544,7 @@ public: SMLoc End; if (Parser.parseExpression(Val, End)) return error("Cannot parse symbol: ", Lexer.getTok()); - Operands.push_back(make_unique<WebAssemblyOperand>( + Operands.push_back(std::make_unique<WebAssemblyOperand>( WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(), WebAssemblyOperand::SymOp{Val})); if (checkForP2AlignIfLoadStore(Operands, Name)) @@ -549,7 +579,7 @@ public: } case AsmToken::LCurly: { Parser.Lex(); - auto Op = make_unique<WebAssemblyOperand>( + auto Op = std::make_unique<WebAssemblyOperand>( WebAssemblyOperand::BrList, Tok.getLoc(), Tok.getEndLoc()); if (!Lexer.is(AsmToken::RCurly)) for (;;) { @@ -572,7 +602,7 @@ public: } if (ExpectBlockType && Operands.size() == 1) { // Support blocks with no operands as default to void. - addBlockTypeOperand(Operands, NameLoc, WebAssembly::ExprType::Void); + addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void); } Parser.Lex(); return false; @@ -671,7 +701,7 @@ public: LastFunctionLabel = LastLabel; push(Function); } - auto Signature = make_unique<wasm::WasmSignature>(); + auto Signature = std::make_unique<wasm::WasmSignature>(); if (parseSignature(Signature.get())) return true; WasmSym->setSignature(Signature.get()); @@ -687,7 +717,7 @@ public: if (SymName.empty()) return true; auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName)); - auto Signature = make_unique<wasm::WasmSignature>(); + auto Signature = std::make_unique<wasm::WasmSignature>(); if (parseRegTypeList(Signature->Params)) return true; WasmSym->setSignature(Signature.get()); @@ -737,24 +767,30 @@ public: return true; // We didn't process this directive. } + // Called either when the first instruction is parsed of the function ends. + void ensureLocals(MCStreamer &Out) { + if (CurrentState == FunctionStart) { + // We haven't seen a .local directive yet. The streamer requires locals to + // be encoded as a prelude to the instructions, so emit an empty list of + // locals here. + auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>( + *Out.getTargetStreamer()); + TOut.emitLocal(SmallVector<wasm::ValType, 0>()); + CurrentState = FunctionLocals; + } + } + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) override { MCInst Inst; + Inst.setLoc(IDLoc); unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); switch (MatchResult) { case Match_Success: { - if (CurrentState == FunctionStart) { - // This is the first instruction in a function, but we haven't seen - // a .local directive yet. The streamer requires locals to be encoded - // as a prelude to the instructions, so emit an empty list of locals - // here. - auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>( - *Out.getTargetStreamer()); - TOut.emitLocal(SmallVector<wasm::ValType, 0>()); - } + ensureLocals(Out); // Fix unknown p2align operands. auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode()); if (Align != -1U) { |