forked from OSchip/llvm-project
[WebAssembly] made assembler parse block_type
Summary: This was previously ignored and an incorrect value generated. Also fixed Disassembler's handling of block_type. Reviewers: dschuff, aheejin Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits Differential Revision: https://reviews.llvm.org/D56092 llvm-svn: 350270
This commit is contained in:
parent
33e3b4b9b3
commit
ad72f68501
|
@ -301,6 +301,18 @@ 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("except_ref", WebAssembly::ExprType::ExceptRef)
|
||||
.Case("void", WebAssembly::ExprType::Void)
|
||||
.Default(WebAssembly::ExprType::Invalid);
|
||||
}
|
||||
|
||||
bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &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>(
|
||||
WebAssemblyOperand::Integer, NameLoc, NameLoc,
|
||||
WebAssemblyOperand::IntOp{static_cast<int64_t>(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>(
|
||||
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>(
|
||||
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>(
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<uint8_t>(MI, Size, Bytes))
|
||||
return MCDisassembler::Fail;
|
||||
break;
|
||||
}
|
||||
// FP operands.
|
||||
case WebAssembly::OPERAND_F32IMM: {
|
||||
if (!parseImmediate<float>(MI, Size, Bytes))
|
||||
|
|
|
@ -278,6 +278,8 @@ void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI,
|
|||
case WebAssembly::ExprType::ExceptRef:
|
||||
O << "except_ref";
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("invalid WebAssembly::ExprType");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue