llvm.org GIT mirror llvm / a177499
[WebAssembly] Added initial AsmParser implementation. It uses the MC framework and the tablegen matcher to do the heavy lifting. Can handle both explicit and implicit locals (-disable-wasm-explicit-locals). Comes with a small regression test. This is a first basic implementation that can parse most llvm .s output and round-trips most instructions succesfully, but in order to keep the commit small, does not address all issues. There are a fair number of mismatches between what MC / assembly matcher think a "CPU" should look like and what WASM provides, some already have workarounds in this commit (e.g. the way it deals with register operands) and some that require further work. Some of that further work may involve changing what the Disassembler outputs (and what s2wasm parses), so are probably best left to followups. Some known things missing: - Many directives are ignored and not emitted. - Vararg calls are parsed but extra args not emitted. - Loop signatures are likely incorrect. - $drop= is not emitted. - Disassembler does not output SIMD types correctly, so assembler can't test them. Patch by Wouter van Oortmerssen Differential Revision: https://reviews.llvm.org/D44329 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@328028 91177308-0d34-0410-b5e6-96231b3b80d8 Derek Schuff 2 years ago
10 changed file(s) with 686 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
398398 .Case("lo8", VK_AVR_LO8)
399399 .Case("hi8", VK_AVR_HI8)
400400 .Case("hlo8", VK_AVR_HLO8)
401 .Case("function", VK_WebAssembly_FUNCTION)
402 .Case("typeindex", VK_WebAssembly_TYPEINDEX)
401403 .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO)
402404 .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI)
403405 .Case("rel32@lo", VK_AMDGPU_REL32_LO)
0 add_llvm_library(LLVMWebAssemblyAsmParser
1 WebAssemblyAsmParser.cpp
2 )
0 ;===-- ./lib/Target/WebAssembly/Disassembler/LLVMBuild.txt -----*- Conf -*--===;
1 ;
2 ; The LLVM Compiler Infrastructure
3 ;
4 ; This file is distributed under the University of Illinois Open Source
5 ; License. See LICENSE.TXT for details.
6 ;
7 ;===------------------------------------------------------------------------===;
8 ;
9 ; This is an LLVMBuild description file for the components in this subdirectory.
10 ;
11 ; For more information on the LLVMBuild system, please see:
12 ;
13 ; http://llvm.org/docs/LLVMBuild.html
14 ;
15 ;===------------------------------------------------------------------------===;
16
17 [component_0]
18 type = Library
19 name = WebAssemblyAsmParser
20 parent = WebAssembly
21 required_libraries = MC MCParser WebAssemblyInfo Support
22 add_to_library_groups = WebAssembly
0 //==- WebAssemblyAsmParser.cpp - Assembler for WebAssembly -*- C++ -*-==//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// \brief This file is part of the WebAssembly Assembler.
11 ///
12 /// It contains code to translate a parsed .s file into MCInsts.
13 ///
14 //===----------------------------------------------------------------------===//
15
16 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17 #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
18 #include "WebAssembly.h"
19 #include "llvm/MC/MCContext.h"
20 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
21 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
22 #include "llvm/MC/MCInst.h"
23 #include "llvm/MC/MCInstrInfo.h"
24 #include "llvm/MC/MCSubtargetInfo.h"
25 #include "llvm/MC/MCSymbol.h"
26 #include "llvm/MC/MCStreamer.h"
27 #include "llvm/Support/Endian.h"
28 #include "llvm/Support/TargetRegistry.h"
29
30 using namespace llvm;
31
32 #define DEBUG_TYPE "wasm-asm-parser"
33
34 namespace {
35
36 // We store register types as SimpleValueType to retain SIMD layout
37 // information, but must also be able to supply them as the (unnamed)
38 // register enum from WebAssemblyRegisterInfo.td/.inc.
39 static unsigned MVTToWasmReg(MVT::SimpleValueType Type) {
40 switch(Type) {
41 case MVT::i32: return WebAssembly::I32_0;
42 case MVT::i64: return WebAssembly::I64_0;
43 case MVT::f32: return WebAssembly::F32_0;
44 case MVT::f64: return WebAssembly::F64_0;
45 case MVT::v16i8: return WebAssembly::V128_0;
46 case MVT::v8i16: return WebAssembly::V128_0;
47 case MVT::v4i32: return WebAssembly::V128_0;
48 case MVT::v4f32: return WebAssembly::V128_0;
49 default: return MVT::INVALID_SIMPLE_VALUE_TYPE;
50 }
51 }
52
53 /// WebAssemblyOperand - Instances of this class represent the operands in a
54 /// parsed WASM machine instruction.
55 struct WebAssemblyOperand : public MCParsedAsmOperand {
56 enum KindTy { Token, Local, Stack, Integer, Float, Symbol } Kind;
57
58 SMLoc StartLoc, EndLoc;
59
60 struct TokOp {
61 StringRef Tok;
62 };
63
64 struct RegOp {
65 // This is a (virtual) local or stack register represented as 0..
66 unsigned RegNo;
67 // In most targets, the register number also encodes the type, but for
68 // wasm we have to track that seperately since we have an unbounded
69 // number of registers.
70 // This has the unfortunate side effect that we supply a different value
71 // to the table-gen matcher at different times in the process (when it
72 // calls getReg() or addRegOperands().
73 // TODO: While this works, it feels brittle. and would be nice to clean up.
74 MVT::SimpleValueType Type;
75 };
76
77 struct IntOp {
78 int64_t Val;
79 };
80
81 struct FltOp {
82 double Val;
83 };
84
85 struct SymOp {
86 const MCExpr *Exp;
87 };
88
89 union {
90 struct TokOp Tok;
91 struct RegOp Reg;
92 struct IntOp Int;
93 struct FltOp Flt;
94 struct SymOp Sym;
95 };
96
97 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, TokOp T)
98 : Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {}
99 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, RegOp R)
100 : Kind(K), StartLoc(Start), EndLoc(End), Reg(R) {}
101 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I)
102 : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {}
103 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F)
104 : Kind(K), StartLoc(Start), EndLoc(End), Flt(F) {}
105 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, SymOp S)
106 : Kind(K), StartLoc(Start), EndLoc(End), Sym(S) {}
107
108 bool isToken() const override { return Kind == Token; }
109 bool isImm() const override { return Kind == Integer ||
110 Kind == Float ||
111 Kind == Symbol; }
112 bool isReg() const override { return Kind == Local || Kind == Stack; }
113 bool isMem() const override { return false; }
114
115 unsigned getReg() const override {
116 assert(isReg());
117 // This is called from the tablegen matcher (MatchInstructionImpl)
118 // where it expects to match the type of register, see RegOp above.
119 return MVTToWasmReg(Reg.Type);
120 }
121
122 StringRef getToken() const {
123 assert(isToken());
124 return Tok.Tok;
125 }
126
127 SMLoc getStartLoc() const override { return StartLoc; }
128 SMLoc getEndLoc() const override { return EndLoc; }
129
130 void addRegOperands(MCInst &Inst, unsigned N) const {
131 assert(N == 1 && "Invalid number of operands!");
132 assert(isReg() && "Not a register operand!");
133 // This is called from the tablegen matcher (MatchInstructionImpl)
134 // where it expects to output the actual register index, see RegOp above.
135 unsigned R = Reg.RegNo;
136 if (Kind == Stack) {
137 // A stack register is represented as a large negative number.
138 // See WebAssemblyRegNumbering::runOnMachineFunction and
139 // getWARegStackId for why this | is needed.
140 R |= INT32_MIN;
141 }
142 Inst.addOperand(MCOperand::createReg(R));
143 }
144
145 void addImmOperands(MCInst &Inst, unsigned N) const {
146 assert(N == 1 && "Invalid number of operands!");
147 if (Kind == Integer)
148 Inst.addOperand(MCOperand::createImm(Int.Val));
149 else if (Kind == Float)
150 Inst.addOperand(MCOperand::createFPImm(Flt.Val));
151 else if (Kind == Symbol)
152 Inst.addOperand(MCOperand::createExpr(Sym.Exp));
153 else
154 llvm_unreachable("Should be immediate or symbol!");
155 }
156
157 void print(raw_ostream &OS) const override {
158 switch (Kind) {
159 case Token:
160 OS << "Tok:" << Tok.Tok;
161 break;
162 case Local:
163 OS << "Loc:" << Reg.RegNo << ":" << static_cast(Reg.Type);
164 break;
165 case Stack:
166 OS << "Stk:" << Reg.RegNo << ":" << static_cast(Reg.Type);
167 break;
168 case Integer:
169 OS << "Int:" << Int.Val;
170 break;
171 case Float:
172 OS << "Flt:" << Flt.Val;
173 break;
174 case Symbol:
175 OS << "Sym:" << Sym.Exp;
176 break;
177 }
178 }
179 };
180
181 class WebAssemblyAsmParser final : public MCTargetAsmParser {
182 MCAsmParser &Parser;
183 MCAsmLexer &Lexer;
184 // These are for the current function being parsed:
185 // These are vectors since register assignments are so far non-sparse.
186 // Replace by map if necessary.
187 std::vector LocalTypes;
188 std::vector StackTypes;
189 MCSymbol *LastLabel;
190
191 public:
192 WebAssemblyAsmParser(const MCSubtargetInfo &sti, MCAsmParser &Parser,
193 const MCInstrInfo &mii, const MCTargetOptions &Options)
194 : MCTargetAsmParser(Options, sti, mii), Parser(Parser),
195 Lexer(Parser.getLexer()), LastLabel(nullptr) {
196 }
197
198 #define GET_ASSEMBLER_HEADER
199 #include "WebAssemblyGenAsmMatcher.inc"
200
201 // TODO: This is required to be implemented, but appears unused.
202 bool ParseRegister(unsigned &/*RegNo*/, SMLoc &/*StartLoc*/,
203 SMLoc &/*EndLoc*/) override {
204 llvm_unreachable("ParseRegister is not implemented.");
205 }
206
207 bool Error(const StringRef &msg, const AsmToken &tok) {
208 return Parser.Error(tok.getLoc(), msg + tok.getString());
209 }
210
211 bool IsNext(AsmToken::TokenKind Kind) {
212 auto ok = Lexer.is(Kind);
213 if (ok) Parser.Lex();
214 return ok;
215 }
216
217 bool Expect(AsmToken::TokenKind Kind, const char *KindName) {
218 if (!IsNext(Kind))
219 return Error(std::string("Expected ") + KindName + ", instead got: ",
220 Lexer.getTok());
221 return false;
222 }
223
224 MVT::SimpleValueType ParseRegType(const StringRef &RegType) {
225 // Derive type from .param .local decls, or the instruction itself.
226 return StringSwitch(RegType)
227 .Case("i32", MVT::i32)
228 .Case("i64", MVT::i64)
229 .Case("f32", MVT::f32)
230 .Case("f64", MVT::f64)
231 .Case("i8x16", MVT::v16i8)
232 .Case("i16x8", MVT::v8i16)
233 .Case("i32x4", MVT::v4i32)
234 .Case("f32x4", MVT::v4f32)
235 .Default(MVT::INVALID_SIMPLE_VALUE_TYPE);
236 }
237
238 MVT::SimpleValueType &GetType(
239 std::vector &Types, size_t i) {
240 Types.resize(std::max(i + 1, Types.size()), MVT::INVALID_SIMPLE_VALUE_TYPE);
241 return Types[i];
242 }
243
244 bool ParseReg(OperandVector &Operands, StringRef TypePrefix) {
245 if (Lexer.is(AsmToken::Integer)) {
246 auto &Local = Lexer.getTok();
247 // This is a reference to a local, turn it into a virtual register.
248 auto LocalNo = static_cast(Local.getIntVal());
249 Operands.push_back(make_unique(
250 WebAssemblyOperand::Local, Local.getLoc(),
251 Local.getEndLoc(),
252 WebAssemblyOperand::RegOp{LocalNo,
253 GetType(LocalTypes, LocalNo)}));
254 Parser.Lex();
255 } else if (Lexer.is(AsmToken::Identifier)) {
256 auto &StackRegTok = Lexer.getTok();
257 // These are push/pop/drop pseudo stack registers, which we turn
258 // into virtual registers also. The stackify pass will later turn them
259 // back into implicit stack references if possible.
260 auto StackReg = StackRegTok.getString();
261 auto StackOp = StackReg.take_while([](char c) { return isalpha(c); });
262 auto Reg = StackReg.drop_front(StackOp.size());
263 unsigned long long ParsedRegNo = 0;
264 if (!Reg.empty() && getAsUnsignedInteger(Reg, 10, ParsedRegNo))
265 return Error("Cannot parse stack register index: ", StackRegTok);
266 unsigned RegNo = static_cast(ParsedRegNo);
267 if (StackOp == "push") {
268 // This defines a result, record register type.
269 auto RegType = ParseRegType(TypePrefix);
270 GetType(StackTypes, RegNo) = RegType;
271 Operands.push_back(make_unique(
272 WebAssemblyOperand::Stack,
273 StackRegTok.getLoc(),
274 StackRegTok.getEndLoc(),
275 WebAssemblyOperand::RegOp{RegNo, RegType}));
276 } else if (StackOp == "pop") {
277 // This uses a previously defined stack value.
278 auto RegType = GetType(StackTypes, RegNo);
279 Operands.push_back(make_unique(
280 WebAssemblyOperand::Stack,
281 StackRegTok.getLoc(),
282 StackRegTok.getEndLoc(),
283 WebAssemblyOperand::RegOp{RegNo, RegType}));
284 } else if (StackOp == "drop") {
285 // This operand will be dropped, since it is part of an instruction
286 // whose result is void.
287 } else {
288 return Error("Unknown stack register prefix: ", StackRegTok);
289 }
290 Parser.Lex();
291 } else {
292 return Error(
293 "Expected identifier/integer following $, instead got: ",
294 Lexer.getTok());
295 }
296 IsNext(AsmToken::Equal);
297 return false;
298 }
299
300 void ParseSingleInteger(bool IsNegative, OperandVector &Operands) {
301 auto &Int = Lexer.getTok();
302 int64_t Val = Int.getIntVal();
303 if (IsNegative) Val = -Val;
304 Operands.push_back(make_unique(
305 WebAssemblyOperand::Integer, Int.getLoc(),
306 Int.getEndLoc(), WebAssemblyOperand::IntOp{Val}));
307 Parser.Lex();
308 }
309
310 bool ParseOperandStartingWithInteger(bool IsNegative,
311 OperandVector &Operands,
312 StringRef InstType) {
313 ParseSingleInteger(IsNegative, Operands);
314 if (Lexer.is(AsmToken::LParen)) {
315 // Parse load/store operands of the form: offset($reg)align
316 auto &LParen = Lexer.getTok();
317 Operands.push_back(
318 make_unique(WebAssemblyOperand::Token,
319 LParen.getLoc(),
320 LParen.getEndLoc(),
321 WebAssemblyOperand::TokOp{
322 LParen.getString()}));
323 Parser.Lex();
324 if (Expect(AsmToken::Dollar, "register")) return true;
325 if (ParseReg(Operands, InstType)) return true;
326 auto &RParen = Lexer.getTok();
327 Operands.push_back(
328 make_unique(WebAssemblyOperand::Token,
329 RParen.getLoc(),
330 RParen.getEndLoc(),
331 WebAssemblyOperand::TokOp{
332 RParen.getString()}));
333 if (Expect(AsmToken::RParen, ")")) return true;
334 if (Lexer.is(AsmToken::Integer)) {
335 ParseSingleInteger(false, Operands);
336 } else {
337 // Alignment not specified.
338 // FIXME: correctly derive a default from the instruction.
339 Operands.push_back(make_unique(
340 WebAssemblyOperand::Integer, RParen.getLoc(),
341 RParen.getEndLoc(), WebAssemblyOperand::IntOp{0}));
342 }
343 }
344 return false;
345 }
346
347 bool ParseInstruction(ParseInstructionInfo &/*Info*/, StringRef Name,
348 SMLoc NameLoc, OperandVector &Operands) override {
349 Operands.push_back(
350 make_unique(WebAssemblyOperand::Token, NameLoc,
351 SMLoc::getFromPointer(
352 NameLoc.getPointer() + Name.size()),
353 WebAssemblyOperand::TokOp{
354 StringRef(NameLoc.getPointer(),
355 Name.size())}));
356 auto NamePair = Name.split('.');
357 // If no '.', there is no type prefix.
358 if (NamePair.second.empty()) std::swap(NamePair.first, NamePair.second);
359 while (Lexer.isNot(AsmToken::EndOfStatement)) {
360 auto &Tok = Lexer.getTok();
361 switch (Tok.getKind()) {
362 case AsmToken::Dollar: {
363 Parser.Lex();
364 if (ParseReg(Operands, NamePair.first)) return true;
365 break;
366 }
367 case AsmToken::Identifier: {
368 auto &Id = Lexer.getTok();
369 const MCExpr *Val;
370 SMLoc End;
371 if (Parser.parsePrimaryExpr(Val, End))
372 return Error("Cannot parse symbol: ", Lexer.getTok());
373 Operands.push_back(make_unique(
374 WebAssemblyOperand::Symbol, Id.getLoc(),
375 Id.getEndLoc(), WebAssemblyOperand::SymOp{Val}));
376 break;
377 }
378 case AsmToken::Minus:
379 Parser.Lex();
380 if (Lexer.isNot(AsmToken::Integer))
381 return Error("Expected integer instead got: ", Lexer.getTok());
382 if (ParseOperandStartingWithInteger(true, Operands, NamePair.first))
383 return true;
384 break;
385 case AsmToken::Integer:
386 if (ParseOperandStartingWithInteger(false, Operands, NamePair.first))
387 return true;
388 break;
389 case AsmToken::Real: {
390 double Val;
391 if (Tok.getString().getAsDouble(Val, false))
392 return Error("Cannot parse real: ", Tok);
393 Operands.push_back(make_unique(
394 WebAssemblyOperand::Float, Tok.getLoc(),
395 Tok.getEndLoc(), WebAssemblyOperand::FltOp{Val}));
396 Parser.Lex();
397 break;
398 }
399 default:
400 return Error("Unexpected token in operand: ", Tok);
401 }
402 if (Lexer.isNot(AsmToken::EndOfStatement)) {
403 if (Expect(AsmToken::Comma, ",")) return true;
404 }
405 }
406 Parser.Lex();
407 // Call instructions are vararg, but the tablegen matcher doesn't seem to
408 // support that, so for now we strip these extra operands.
409 // This is problematic if these arguments are not simple $pop stack
410 // registers, since e.g. a local register would get lost, so we check for
411 // this. This can be the case when using -disable-wasm-explicit-locals
412 // which currently s2wasm requires.
413 // TODO: Instead, we can move this code to MatchAndEmitInstruction below and
414 // actually generate get_local instructions on the fly.
415 // Or even better, improve the matcher to support vararg?
416 auto IsIndirect = NamePair.second == "call_indirect";
417 if (IsIndirect || NamePair.second == "call") {
418 // Figure out number of fixed operands from the instruction.
419 size_t CallOperands = 1; // The name token.
420 if (!IsIndirect) CallOperands++; // The function index.
421 if (!NamePair.first.empty()) CallOperands++; // The result register.
422 if (Operands.size() > CallOperands) {
423 // Ensure operands we drop are all $pop.
424 for (size_t I = CallOperands; I < Operands.size(); I++) {
425 auto Operand =
426 reinterpret_cast(Operands[I].get());
427 if (Operand->Kind != WebAssemblyOperand::Stack)
428 Parser.Error(NameLoc,
429 "Call instruction has non-stack arguments, if this code was "
430 "generated with -disable-wasm-explicit-locals please remove it");
431 }
432 // Drop unneeded operands.
433 Operands.resize(CallOperands);
434 }
435 }
436 // Block instructions require a signature index, but these are missing in
437 // assembly, so we add a dummy one explicitly (since we have no control
438 // over signature tables here, we assume these will be regenerated when
439 // the wasm module is generated).
440 if (NamePair.second == "block" || NamePair.second == "loop") {
441 Operands.push_back(make_unique(
442 WebAssemblyOperand::Integer, NameLoc,
443 NameLoc, WebAssemblyOperand::IntOp{-1}));
444 }
445 // These don't specify the type, which has to derived from the local index.
446 if (NamePair.second == "get_local" || NamePair.second == "tee_local") {
447 if (Operands.size() >= 3 && Operands[1]->isReg() &&
448 Operands[2]->isImm()) {
449 auto Op1 = reinterpret_cast(Operands[1].get());
450 auto Op2 = reinterpret_cast(Operands[2].get());
451 auto Type = GetType(LocalTypes, static_cast(Op2->Int.Val));
452 Op1->Reg.Type = Type;
453 GetType(StackTypes, Op1->Reg.RegNo) = Type;
454 }
455 }
456 return false;
457 }
458
459 void onLabelParsed(MCSymbol *Symbol) override {
460 LastLabel = Symbol;
461 }
462
463 bool ParseDirective(AsmToken DirectiveID) override {
464 assert(DirectiveID.getKind() == AsmToken::Identifier);
465 auto &Out = getStreamer();
466 auto &TOut = reinterpret_cast(
467 *Out.getTargetStreamer());
468 // TODO: we're just parsing the subset of directives we're interested in,
469 // and ignoring ones we don't recognise. We should ideally verify
470 // all directives here.
471 if (DirectiveID.getString() == ".type") {
472 // This could be the start of a function, check if followed by
473 // "label,@function"
474 if (!(IsNext(AsmToken::Identifier) &&
475 IsNext(AsmToken::Comma) &&
476 IsNext(AsmToken::At) &&
477 Lexer.is(AsmToken::Identifier)))
478 return Error("Expected label,@type declaration, got: ", Lexer.getTok());
479 if (Lexer.getTok().getString() == "function") {
480 // Track locals from start of function.
481 LocalTypes.clear();
482 StackTypes.clear();
483 }
484 Parser.Lex();
485 //Out.EmitSymbolAttribute(??, MCSA_ELF_TypeFunction);
486 } else if (DirectiveID.getString() == ".param" ||
487 DirectiveID.getString() == ".local") {
488 // Track the number of locals, needed for correct virtual register
489 // assignment elsewhere.
490 // Also output a directive to the streamer.
491 std::vector Params;
492 std::vector Locals;
493 while (Lexer.is(AsmToken::Identifier)) {
494 auto RegType = ParseRegType(Lexer.getTok().getString());
495 if (RegType == MVT::INVALID_SIMPLE_VALUE_TYPE) return true;
496 LocalTypes.push_back(RegType);
497 if (DirectiveID.getString() == ".param") {
498 Params.push_back(RegType);
499 } else {
500 Locals.push_back(RegType);
501 }
502 Parser.Lex();
503 if (!IsNext(AsmToken::Comma)) break;
504 }
505 assert(LastLabel);
506 TOut.emitParam(LastLabel, Params);
507 TOut.emitLocal(Locals);
508 } else {
509 // For now, ignore anydirective we don't recognize:
510 while (Lexer.isNot(AsmToken::EndOfStatement)) Parser.Lex();
511 }
512 return Expect(AsmToken::EndOfStatement, "EOL");
513 }
514
515 bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &/*Opcode*/,
516 OperandVector &Operands,
517 MCStreamer &Out, uint64_t &ErrorInfo,
518 bool MatchingInlineAsm) override {
519 MCInst Inst;
520 unsigned MatchResult =
521 MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
522 switch (MatchResult) {
523 case Match_Success: {
524 Out.EmitInstruction(Inst, getSTI());
525 return false;
526 }
527 case Match_MissingFeature:
528 return Parser.Error(IDLoc,
529 "instruction requires a WASM feature not currently enabled");
530 case Match_MnemonicFail:
531 return Parser.Error(IDLoc, "invalid instruction");
532 case Match_NearMisses:
533 return Parser.Error(IDLoc, "ambiguous instruction");
534 case Match_InvalidTiedOperand:
535 case Match_InvalidOperand: {
536 SMLoc ErrorLoc = IDLoc;
537 if (ErrorInfo != ~0ULL) {
538 if (ErrorInfo >= Operands.size())
539 return Parser.Error(IDLoc, "too few operands for instruction");
540 ErrorLoc = Operands[ErrorInfo]->getStartLoc();
541 if (ErrorLoc == SMLoc())
542 ErrorLoc = IDLoc;
543 }
544 return Parser.Error(ErrorLoc, "invalid operand for instruction");
545 }
546 }
547 llvm_unreachable("Implement any new match types added!");
548 }
549 };
550 } // end anonymous namespace
551
552 // Force static initialization.
553 extern "C" void LLVMInitializeWebAssemblyAsmParser() {
554 RegisterMCAsmParser X(getTheWebAssemblyTarget32());
555 RegisterMCAsmParser Y(getTheWebAssemblyTarget64());
556 }
557
558 #define GET_REGISTER_MATCHER
559 #define GET_MATCHER_IMPLEMENTATION
560 #include "WebAssemblyGenAsmMatcher.inc"
66 tablegen(LLVM WebAssemblyGenMCCodeEmitter.inc -gen-emitter)
77 tablegen(LLVM WebAssemblyGenRegisterInfo.inc -gen-register-info)
88 tablegen(LLVM WebAssemblyGenSubtargetInfo.inc -gen-subtarget)
9 tablegen(LLVM WebAssemblyGenAsmMatcher.inc -gen-asm-matcher)
910 add_public_tablegen_target(WebAssemblyCommonTableGen)
1011
1112 add_llvm_target(WebAssemblyCodeGen
5051 intrinsics_gen
5152 )
5253
54 add_subdirectory(AsmParser)
5355 add_subdirectory(Disassembler)
5456 add_subdirectory(InstPrinter)
5557 add_subdirectory(MCTargetDesc)
8181 ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
8282 break;
8383 case WebAssembly::END_LOOP:
84 ControlFlowStack.pop_back();
84 // Have to guard against an empty stack, in case of mismatched pairs
85 // in assembly parsing.
86 if (!ControlFlowStack.empty()) ControlFlowStack.pop_back();
8587 break;
8688 case WebAssembly::END_BLOCK:
87 printAnnotation(
89 if (!ControlFlowStack.empty()) printAnnotation(
8890 OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
8991 break;
9092 }
1515 ;===------------------------------------------------------------------------===;
1616
1717 [common]
18 subdirectories = Disassembler InstPrinter MCTargetDesc TargetInfo
18 subdirectories = AsmParser Disassembler InstPrinter MCTargetDesc TargetInfo
1919
2020 [component_0]
2121 type = TargetGroup
2222 name = WebAssembly
2323 parent = Target
24 has_asmparser = 1
2425 has_asmprinter = 1
2526 has_disassembler = 1
2627
7979 def WebAssembly : Target {
8080 let InstructionSet = WebAssemblyInstrInfo;
8181 }
82
83 def WebAssemblyAsmParser : AsmParser {
84 // The physical register names are not in the binary format or asm text
85 let ShouldEmitMatchRegisterName = 0;
86 }
3333 def SP64 : WebAssemblyReg<"%SP64">;
3434
3535 // The register allocation framework requires register classes have at least
36 // one register, so we define a few for the floating point register classes
37 // since we otherwise don't need a physical register in those classes.
36 // one register, so we define a few for the integer / floating point register
37 // classes since we otherwise don't need a physical register in those classes.
38 // These are also used a "types" in the generated assembly matcher.
39 def I32_0 : WebAssemblyReg<"%i32.0">;
40 def I64_0 : WebAssemblyReg<"%i64.0">;
3841 def F32_0 : WebAssemblyReg<"%f32.0">;
3942 def F64_0 : WebAssemblyReg<"%f64.0">;
43
4044 def V128_0: WebAssemblyReg<"%v128">;
45
4146 def EXCEPT_REF_0 : WebAssemblyReg<"%except_ref.0">;
4247
4348 // The value stack "register". This is an opaque entity which serves to order
5358 // Register classes
5459 //===----------------------------------------------------------------------===//
5560
56 def I32 : WebAssemblyRegClass<[i32], 32, (add FP32, SP32)>;
57 def I64 : WebAssemblyRegClass<[i64], 64, (add FP64, SP64)>;
61 def I32 : WebAssemblyRegClass<[i32], 32, (add FP32, SP32, I32_0)>;
62 def I64 : WebAssemblyRegClass<[i64], 64, (add FP64, SP64, I64_0)>;
5863 def F32 : WebAssemblyRegClass<[f32], 32, (add F32_0)>;
5964 def F64 : WebAssemblyRegClass<[f64], 64, (add F64_0)>;
6065 def V128 : WebAssemblyRegClass<[v4f32, v4i32, v16i8, v8i16], 128, (add V128_0)>;
6166 def EXCEPT_REF : WebAssemblyRegClass<[ExceptRef], 0, (add EXCEPT_REF_0)>;
67
0 # RUN: llvm-mc -triple=wasm32-unknown-unknown-elf < %s | FileCheck %s
1
2 .text
3 .type test0,@function
4 test0:
5 # Test all types:
6 .param i32, i64
7 .local f32, f64 #, i8x16, i16x8, i32x4, f32x4
8 # Explicit getlocal/setlocal:
9 get_local $push0=, 2
10 set_local 2, $pop0=
11 # Implicit locals & immediates:
12 i32.const $0=, -1
13 f64.const $3=, 0x1.999999999999ap1
14 # Indirect addressing:
15 get_local $push1=, 0
16 f64.store 0($pop1), $3
17 # Loops, conditionals, binary ops, calls etc:
18 block
19 i32.const $push2=, 1
20 get_local $push7=, 0
21 i32.ge_s $push0=, $pop2, $pop7
22 br_if 0, $pop0 # 0: down to label0
23 .LBB0_1:
24 loop # label1:
25 call $drop=, something1@FUNCTION
26 i64.const $push10=, 1234
27 i32.call $push8=, something2@FUNCTION, $pop10
28 i32.const $push11=, 0
29 call_indirect $pop11
30 i32.const $push5=, 1
31 i32.add $push4=, $pop8, $pop5
32 tee_local $push3=, 0, $pop4
33 get_local $push9=, 0
34 i32.lt_s $push1=, $pop3, $pop9
35 br_if 0, $pop1 # 0: up to label1
36 .LBB0_2:
37 end_loop
38 end_block # label0:
39 end_function
40
41
42 # CHECK: .text
43 # CHECK-LABEL: test0:
44 # CHECK-NEXT: .param i32, i64
45 # CHECK-NEXT: .local f32, f64
46 # CHECK-NEXT: get_local $push0=, 2
47 # CHECK-NEXT: set_local 2, $pop0
48 # CHECK-NEXT: i32.const $0=, -1
49 # CHECK-NEXT: f64.const $3=, 0x1.999999999999ap1
50 # CHECK-NEXT: get_local $push1=, 0
51 # CHECK-NEXT: f64.store 0($pop1):p2align=0, $3
52 # CHECK-NEXT: block
53 # CHECK-NEXT: i32.const $push2=, 1
54 # CHECK-NEXT: get_local $push7=, 0
55 # CHECK-NEXT: i32.ge_s $push0=, $pop2, $pop7
56 # CHECK-NEXT: br_if 0, $pop0 # 0: down to label0
57 # CHECK-NEXT: .LBB0_1:
58 # CHECK-NEXT: loop # label1:
59 # CHECK-NEXT: call something1@FUNCTION
60 # CHECK-NEXT: i64.const $push10=, 1234
61 # CHECK-NEXT: i32.call $push8=, something2@FUNCTION
62 # CHECK-NEXT: i32.const $push11=, 0
63 # CHECK-NEXT: call_indirect
64 # CHECK-NEXT: i32.const $push5=, 1
65 # CHECK-NEXT: i32.add $push4=, $pop8, $pop5
66 # CHECK-NEXT: tee_local $push3=, 0, $pop4
67 # CHECK-NEXT: get_local $push9=, 0
68 # CHECK-NEXT: i32.lt_s $push1=, $pop3, $pop9
69 # CHECK-NEXT: br_if 0, $pop1 # 0: up to label1
70 # CHECK-NEXT: .LBB0_2:
71 # CHECK-NEXT: end_loop
72 # CHECK-NEXT: end_block # label0:
73 # CHECK-NEXT: end_function