diff --git a/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index d997190aa36..0a5908f4379 100644 --- a/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -301,6 +301,18 @@ public: return Optional(); } + WebAssembly::ExprType parseBlockType(StringRef ID) { + return StringSwitch(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("except_ref", WebAssembly::ExprType::ExceptRef) + .Case("void", WebAssembly::ExprType::Void) + .Default(WebAssembly::ExprType::Invalid); + } + bool parseRegTypeList(SmallVectorImpl &Types) { while (Lexer.is(AsmToken::Identifier)) { auto Type = parseType(Lexer.getTok().getString()); @@ -351,6 +363,13 @@ public: return false; } + void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc, + WebAssembly::ExprType BT) { + Operands.push_back(make_unique( + WebAssemblyOperand::Integer, NameLoc, NameLoc, + WebAssemblyOperand::IntOp{static_cast(BT)})); + } + bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override { // Note: Name does NOT point into the sourcecode, but to a local, so @@ -387,14 +406,19 @@ public: // If this instruction is part of a control flow structure, ensure // proper nesting. + bool ExpectBlockType = false; if (BaseName == "block") { push(Block); + ExpectBlockType = true; } else if (BaseName == "loop") { push(Loop); + ExpectBlockType = true; } else if (BaseName == "try") { push(Try); + ExpectBlockType = true; } else if (BaseName == "if") { push(If); + ExpectBlockType = true; } else if (BaseName == "else") { if (pop(BaseName, If)) return true; @@ -429,13 +453,23 @@ public: switch (Tok.getKind()) { case AsmToken::Identifier: { auto &Id = Lexer.getTok(); - const MCExpr *Val; - SMLoc End; - if (Parser.parsePrimaryExpr(Val, End)) - return error("Cannot parse symbol: ", Lexer.getTok()); - Operands.push_back(make_unique( - WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(), - WebAssemblyOperand::SymOp{Val})); + if (ExpectBlockType) { + // Assume this identifier is a block_type. + auto BT = parseBlockType(Id.getString()); + if (BT == WebAssembly::ExprType::Invalid) + return error("Unknown block type: ", Id); + addBlockTypeOperand(Operands, NameLoc, BT); + Parser.Lex(); + } else { + // Assume this identifier is a label. + const MCExpr *Val; + SMLoc End; + if (Parser.parsePrimaryExpr(Val, End)) + return error("Cannot parse symbol: ", Lexer.getTok()); + Operands.push_back(make_unique( + WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(), + WebAssemblyOperand::SymOp{Val})); + } break; } case AsmToken::Minus: @@ -482,18 +516,11 @@ public: return true; } } - Parser.Lex(); - - // 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 - // the wasm module is generated). - if (BaseName == "block" || BaseName == "loop" || BaseName == "try" || - BaseName == "if") { - Operands.push_back(make_unique( - WebAssemblyOperand::Integer, NameLoc, NameLoc, - WebAssemblyOperand::IntOp{-1})); + if (ExpectBlockType && Operands.size() == 1) { + // Support blocks with no operands as default to void. + addBlockTypeOperand(Operands, NameLoc, WebAssembly::ExprType::Void); } + Parser.Lex(); return false; } diff --git a/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp index c068d6b43d4..369954b88c9 100644 --- a/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp +++ b/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp @@ -167,12 +167,17 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction( } // SLEB operands: case WebAssembly::OPERAND_I32IMM: - case WebAssembly::OPERAND_I64IMM: - case WebAssembly::OPERAND_SIGNATURE: { + case WebAssembly::OPERAND_I64IMM: { if (!parseLEBImmediate(MI, Size, Bytes, true)) return MCDisassembler::Fail; break; } + // block_type operands (uint8_t). + case WebAssembly::OPERAND_SIGNATURE: { + if (!parseImmediate(MI, Size, Bytes)) + return MCDisassembler::Fail; + break; + } // FP operands. case WebAssembly::OPERAND_F32IMM: { if (!parseImmediate(MI, Size, Bytes)) diff --git a/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp b/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp index eaf9750792b..a2882673060 100644 --- a/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp +++ b/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp @@ -278,6 +278,8 @@ void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI, case WebAssembly::ExprType::ExceptRef: O << "except_ref"; break; + default: + llvm_unreachable("invalid WebAssembly::ExprType"); } } diff --git a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index 4ca20f59368..a111eb51c56 100644 --- a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -346,7 +346,8 @@ enum class ExprType : unsigned { F32 = 0x7D, F64 = 0x7C, V128 = 0x7B, - ExceptRef = 0x68 + ExceptRef = 0x68, + Invalid = 0x00 }; /// Instruction opcodes emitted via means other than CodeGen. diff --git a/test/MC/Disassembler/WebAssembly/wasm.txt b/test/MC/Disassembler/WebAssembly/wasm.txt index fd21db9ad47..6c73933ecd7 100644 --- a/test/MC/Disassembler/WebAssembly/wasm.txt +++ b/test/MC/Disassembler/WebAssembly/wasm.txt @@ -14,10 +14,8 @@ # CHECK: i64.load32_u 16:p2align=1 0x35 0x01 0x10 -# CHECK: block -# 3 -# FIXME: WebAssemblyInstPrinter does not currently print block number. -0x02 0x03 +# CHECK: block f64 +0x02 0x7C # CHECK: call_indirect # $0=, 128, 0 diff --git a/test/MC/WebAssembly/basic-assembly.s b/test/MC/WebAssembly/basic-assembly.s index 684d40debfe..4be32bd5870 100644 --- a/test/MC/WebAssembly/basic-assembly.s +++ b/test/MC/WebAssembly/basic-assembly.s @@ -22,13 +22,13 @@ test0: get_local 0 f64.store 0 # Loops, conditionals, binary ops, calls etc: - block + block i32 i32.const 1 get_local 0 i32.ge_s br_if 0 # 0: down to label0 .LBB0_1: - loop # label1: + loop i32 # label1: call something1@FUNCTION i64.const 1234 i32.call something2@FUNCTION @@ -42,25 +42,25 @@ test0: br_if 0 # 0: up to label1 .LBB0_2: end_loop - end_block # label0: + end_block # label0: get_local 4 get_local 5 - block - block - block - block + block void + block i64 + block f32 + block f64 br_table {0, 1, 2} # 2 entries, default end_block # first entry jumps here. - i32.const 1 + i32.const 1 br 2 end_block # second entry jumps here. - i32.const 2 + i32.const 2 br 1 end_block # default jumps here. - i32.const 3 + i32.const 3 end_block # "switch" exit. - if - if + if # void + if i32 end_if else end_if @@ -69,7 +69,7 @@ test0: # TODO: enable once instruction has been added. #i32x4.trunc_s/f32x4:sat i32.trunc_s/f32 - try + try except_ref .LBB0_3: i32.catch 0 .LBB0_4: @@ -80,7 +80,7 @@ test0: get_global __stack_pointer@GLOBAL end_function .Lfunc_end0: - .size test0, .Lfunc_end0-test0 + .size test0, .Lfunc_end0-test0 .globaltype __stack_pointer, i32 # CHECK: .text @@ -96,13 +96,13 @@ test0: # CHECK-NEXT: v128.const 0, 1, 2, 3, 4, 5, 6, 7 # CHECK-NEXT: get_local 0 # CHECK-NEXT: f64.store 0:p2align=0 -# CHECK-NEXT: block +# CHECK-NEXT: block i32 # CHECK-NEXT: i32.const 1 # CHECK-NEXT: get_local 0 # CHECK-NEXT: i32.ge_s # CHECK-NEXT: br_if 0 # 0: down to label0 # CHECK-NEXT: .LBB0_1: -# CHECK-NEXT: loop # label1: +# CHECK-NEXT: loop i32 # label1: # CHECK-NEXT: call something1@FUNCTION # CHECK-NEXT: i64.const 1234 # CHECK-NEXT: i32.call something2@FUNCTION @@ -120,9 +120,9 @@ test0: # CHECK-NEXT: get_local 4 # CHECK-NEXT: get_local 5 # CHECK-NEXT: block -# CHECK-NEXT: block -# CHECK-NEXT: block -# CHECK-NEXT: block +# CHECK-NEXT: block i64 +# CHECK-NEXT: block f32 +# CHECK-NEXT: block f64 # CHECK-NEXT: br_table {0, 1, 2} # 1: down to label4 # CHECK-NEXT: # 2: down to label3 # CHECK-NEXT: end_block # label5: @@ -135,13 +135,13 @@ test0: # CHECK-NEXT: i32.const 3 # CHECK-NEXT: end_block # label2: # CHECK-NEXT: if -# CHECK-NEXT: if +# CHECK-NEXT: if i32 # CHECK-NEXT: end_if # CHECK-NEXT: else # CHECK-NEXT: end_if # CHECK-NEXT: f32x4.add # CHECK-NEXT: i32.trunc_s/f32 -# CHECK-NEXT: try +# CHECK-NEXT: try except_ref # CHECK-NEXT: .LBB0_3: # CHECK-NEXT: i32.catch 0 # CHECK-NEXT: .LBB0_4: