llvm.org GIT mirror llvm / 34ec218
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@350270 91177308-0d34-0410-b5e6-96231b3b80d8 Wouter van Oortmerssen 8 months ago
6 changed file(s) with 79 addition(s) and 46 deletion(s). Raw diff Collapse all Expand all
298298 Type == "f64x2")
299299 return wasm::ValType::V128;
300300 return Optional();
301 }
302
303 WebAssembly::ExprType parseBlockType(StringRef ID) {
304 return StringSwitch(ID)
305 .Case("i32", WebAssembly::ExprType::I32)
306 .Case("i64", WebAssembly::ExprType::I64)
307 .Case("f32", WebAssembly::ExprType::F32)
308 .Case("f64", WebAssembly::ExprType::F64)
309 .Case("v128", WebAssembly::ExprType::V128)
310 .Case("except_ref", WebAssembly::ExprType::ExceptRef)
311 .Case("void", WebAssembly::ExprType::Void)
312 .Default(WebAssembly::ExprType::Invalid);
301313 }
302314
303315 bool parseRegTypeList(SmallVectorImpl &Types) {
350362 return false;
351363 }
352364
365 void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
366 WebAssembly::ExprType BT) {
367 Operands.push_back(make_unique(
368 WebAssemblyOperand::Integer, NameLoc, NameLoc,
369 WebAssemblyOperand::IntOp{static_cast(BT)}));
370 }
371
353372 bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
354373 SMLoc NameLoc, OperandVector &Operands) override {
355374 // Note: Name does NOT point into the sourcecode, but to a local, so
386405
387406 // If this instruction is part of a control flow structure, ensure
388407 // proper nesting.
408 bool ExpectBlockType = false;
389409 if (BaseName == "block") {
390410 push(Block);
411 ExpectBlockType = true;
391412 } else if (BaseName == "loop") {
392413 push(Loop);
414 ExpectBlockType = true;
393415 } else if (BaseName == "try") {
394416 push(Try);
417 ExpectBlockType = true;
395418 } else if (BaseName == "if") {
396419 push(If);
420 ExpectBlockType = true;
397421 } else if (BaseName == "else") {
398422 if (pop(BaseName, If))
399423 return true;
428452 switch (Tok.getKind()) {
429453 case AsmToken::Identifier: {
430454 auto &Id = Lexer.getTok();
431 const MCExpr *Val;
432 SMLoc End;
433 if (Parser.parsePrimaryExpr(Val, End))
434 return error("Cannot parse symbol: ", Lexer.getTok());
435 Operands.push_back(make_unique(
436 WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(),
437 WebAssemblyOperand::SymOp{Val}));
455 if (ExpectBlockType) {
456 // Assume this identifier is a block_type.
457 auto BT = parseBlockType(Id.getString());
458 if (BT == WebAssembly::ExprType::Invalid)
459 return error("Unknown block type: ", Id);
460 addBlockTypeOperand(Operands, NameLoc, BT);
461 Parser.Lex();
462 } else {
463 // Assume this identifier is a label.
464 const MCExpr *Val;
465 SMLoc End;
466 if (Parser.parsePrimaryExpr(Val, End))
467 return error("Cannot parse symbol: ", Lexer.getTok());
468 Operands.push_back(make_unique(
469 WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(),
470 WebAssemblyOperand::SymOp{Val}));
471 }
438472 break;
439473 }
440474 case AsmToken::Minus:
481515 return true;
482516 }
483517 }
518 if (ExpectBlockType && Operands.size() == 1) {
519 // Support blocks with no operands as default to void.
520 addBlockTypeOperand(Operands, NameLoc, WebAssembly::ExprType::Void);
521 }
484522 Parser.Lex();
485
486 // Block instructions require a signature index, but these are missing in
487 // assembly, so we add a dummy one explicitly (since we have no control
488 // over signature tables here, we assume these will be regenerated when
489 // the wasm module is generated).
490 if (BaseName == "block" || BaseName == "loop" || BaseName == "try" ||
491 BaseName == "if") {
492 Operands.push_back(make_unique(
493 WebAssemblyOperand::Integer, NameLoc, NameLoc,
494 WebAssemblyOperand::IntOp{-1}));
495 }
496523 return false;
497524 }
498525
166166 }
167167 // SLEB operands:
168168 case WebAssembly::OPERAND_I32IMM:
169 case WebAssembly::OPERAND_I64IMM:
169 case WebAssembly::OPERAND_I64IMM: {
170 if (!parseLEBImmediate(MI, Size, Bytes, true))
171 return MCDisassembler::Fail;
172 break;
173 }
174 // block_type operands (uint8_t).
170175 case WebAssembly::OPERAND_SIGNATURE: {
171 if (!parseLEBImmediate(MI, Size, Bytes, true))
176 if (!parseImmediate(MI, Size, Bytes))
172177 return MCDisassembler::Fail;
173178 break;
174179 }
277277 case WebAssembly::ExprType::ExceptRef:
278278 O << "except_ref";
279279 break;
280 default:
281 llvm_unreachable("invalid WebAssembly::ExprType");
280282 }
281283 }
282284
345345 F32 = 0x7D,
346346 F64 = 0x7C,
347347 V128 = 0x7B,
348 ExceptRef = 0x68
348 ExceptRef = 0x68,
349 Invalid = 0x00
349350 };
350351
351352 /// Instruction opcodes emitted via means other than CodeGen.
1313 # CHECK: i64.load32_u 16:p2align=1
1414 0x35 0x01 0x10
1515
16 # CHECK: block
17 # 3
18 # FIXME: WebAssemblyInstPrinter does not currently print block number.
19 0x02 0x03
16 # CHECK: block f64
17 0x02 0x7C
2018
2119 # CHECK: call_indirect
2220 # $0=, 128, 0
2121 get_local 0
2222 f64.store 0
2323 # Loops, conditionals, binary ops, calls etc:
24 block
24 block i32
2525 i32.const 1
2626 get_local 0
2727 i32.ge_s
2828 br_if 0 # 0: down to label0
2929 .LBB0_1:
30 loop # label1:
30 loop i32 # label1:
3131 call something1@FUNCTION
3232 i64.const 1234
3333 i32.call something2@FUNCTION
4141 br_if 0 # 0: up to label1
4242 .LBB0_2:
4343 end_loop
44 end_block # label0:
44 end_block # label0:
4545 get_local 4
4646 get_local 5
47 block
48 block
49 block
50 block
47 block void
48 block i64
49 block f32
50 block f64
5151 br_table {0, 1, 2} # 2 entries, default
5252 end_block # first entry jumps here.
53 i32.const 1
53 i32.const 1
5454 br 2
5555 end_block # second entry jumps here.
56 i32.const 2
56 i32.const 2
5757 br 1
5858 end_block # default jumps here.
59 i32.const 3
59 i32.const 3
6060 end_block # "switch" exit.
61 if
62 if
61 if # void
62 if i32
6363 end_if
6464 else
6565 end_if
6868 # TODO: enable once instruction has been added.
6969 #i32x4.trunc_s/f32x4:sat
7070 i32.trunc_s/f32
71 try
71 try except_ref
7272 .LBB0_3:
7373 i32.catch 0
7474 .LBB0_4:
7979 get_global __stack_pointer@GLOBAL
8080 end_function
8181 .Lfunc_end0:
82 .size test0, .Lfunc_end0-test0
82 .size test0, .Lfunc_end0-test0
8383 .globaltype __stack_pointer, i32
8484
8585 # CHECK: .text
9595 # CHECK-NEXT: v128.const 0, 1, 2, 3, 4, 5, 6, 7
9696 # CHECK-NEXT: get_local 0
9797 # CHECK-NEXT: f64.store 0:p2align=0
98 # CHECK-NEXT: block
98 # CHECK-NEXT: block i32
9999 # CHECK-NEXT: i32.const 1
100100 # CHECK-NEXT: get_local 0
101101 # CHECK-NEXT: i32.ge_s
102102 # CHECK-NEXT: br_if 0 # 0: down to label0
103103 # CHECK-NEXT: .LBB0_1:
104 # CHECK-NEXT: loop # label1:
104 # CHECK-NEXT: loop i32 # label1:
105105 # CHECK-NEXT: call something1@FUNCTION
106106 # CHECK-NEXT: i64.const 1234
107107 # CHECK-NEXT: i32.call something2@FUNCTION
119119 # CHECK-NEXT: get_local 4
120120 # CHECK-NEXT: get_local 5
121121 # CHECK-NEXT: block
122 # CHECK-NEXT: block
123 # CHECK-NEXT: block
124 # CHECK-NEXT: block
122 # CHECK-NEXT: block i64
123 # CHECK-NEXT: block f32
124 # CHECK-NEXT: block f64
125125 # CHECK-NEXT: br_table {0, 1, 2} # 1: down to label4
126126 # CHECK-NEXT: # 2: down to label3
127127 # CHECK-NEXT: end_block # label5:
134134 # CHECK-NEXT: i32.const 3
135135 # CHECK-NEXT: end_block # label2:
136136 # CHECK-NEXT: if
137 # CHECK-NEXT: if
137 # CHECK-NEXT: if i32
138138 # CHECK-NEXT: end_if
139139 # CHECK-NEXT: else
140140 # CHECK-NEXT: end_if
141141 # CHECK-NEXT: f32x4.add
142142 # CHECK-NEXT: i32.trunc_s/f32
143 # CHECK-NEXT: try
143 # CHECK-NEXT: try except_ref
144144 # CHECK-NEXT: .LBB0_3:
145145 # CHECK-NEXT: i32.catch 0
146146 # CHECK-NEXT: .LBB0_4: