[RISCV] Fix mgather -> riscv.masked.strided.load combine not extending indices (...
[llvm-project.git] / llvm / lib / MC / MCParser / COFFMasmParser.cpp
blob8adb0dcddb16a4333affcf66c19d660e20b4cba4
1 //===- COFFMasmParser.cpp - COFF MASM Assembly Parser ---------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/StringRef.h"
10 #include "llvm/ADT/Twine.h"
11 #include "llvm/BinaryFormat/COFF.h"
12 #include "llvm/MC/MCAsmMacro.h"
13 #include "llvm/MC/MCContext.h"
14 #include "llvm/MC/MCParser/MCAsmLexer.h"
15 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
16 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
17 #include "llvm/MC/MCSectionCOFF.h"
18 #include "llvm/MC/MCStreamer.h"
19 #include "llvm/MC/MCSymbolCOFF.h"
20 #include "llvm/MC/SectionKind.h"
21 #include "llvm/Support/Casting.h"
22 #include "llvm/Support/SMLoc.h"
23 #include <cstdint>
24 #include <utility>
26 using namespace llvm;
28 namespace {
30 class COFFMasmParser : public MCAsmParserExtension {
31 template <bool (COFFMasmParser::*HandlerMethod)(StringRef, SMLoc)>
32 void addDirectiveHandler(StringRef Directive) {
33 MCAsmParser::ExtensionDirectiveHandler Handler =
34 std::make_pair(this, HandleDirective<COFFMasmParser, HandlerMethod>);
35 getParser().addDirectiveHandler(Directive, Handler);
38 bool ParseSectionSwitch(StringRef SectionName, unsigned Characteristics,
39 SectionKind Kind);
41 bool ParseSectionSwitch(StringRef SectionName, unsigned Characteristics,
42 SectionKind Kind, StringRef COMDATSymName,
43 COFF::COMDATType Type, Align Alignment);
45 bool ParseDirectiveProc(StringRef, SMLoc);
46 bool ParseDirectiveEndProc(StringRef, SMLoc);
47 bool ParseDirectiveSegment(StringRef, SMLoc);
48 bool ParseDirectiveSegmentEnd(StringRef, SMLoc);
49 bool ParseDirectiveIncludelib(StringRef, SMLoc);
50 bool ParseDirectiveOption(StringRef, SMLoc);
52 bool ParseDirectiveAlias(StringRef, SMLoc);
54 bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
55 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
57 bool IgnoreDirective(StringRef, SMLoc) {
58 while (!getLexer().is(AsmToken::EndOfStatement)) {
59 Lex();
61 return false;
64 void Initialize(MCAsmParser &Parser) override {
65 // Call the base implementation.
66 MCAsmParserExtension::Initialize(Parser);
68 // x64 directives
69 addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveAllocStack>(
70 ".allocstack");
71 addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveEndProlog>(
72 ".endprolog");
74 // Code label directives
75 // label
76 // org
78 // Conditional control flow directives
79 // .break
80 // .continue
81 // .else
82 // .elseif
83 // .endif
84 // .endw
85 // .if
86 // .repeat
87 // .until
88 // .untilcxz
89 // .while
91 // Data allocation directives
92 // align
93 // even
94 // mmword
95 // tbyte
96 // xmmword
97 // ymmword
99 // Listing control directives
100 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref");
101 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".list");
102 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listall");
103 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listif");
104 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacro");
105 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacroall");
106 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nocref");
107 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolist");
108 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistif");
109 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistmacro");
110 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("page");
111 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("subtitle");
112 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".tfcond");
113 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("title");
115 // Macro directives
116 // goto
118 // Miscellaneous directives
119 addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>("alias");
120 // assume
121 // .fpo
122 addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>(
123 "includelib");
124 addDirectiveHandler<&COFFMasmParser::ParseDirectiveOption>("option");
125 // popcontext
126 // pushcontext
127 // .safeseh
129 // Procedure directives
130 addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp");
131 // invoke (32-bit only)
132 addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc");
133 // proto
135 // Processor directives; all ignored
136 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386");
137 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386p");
138 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".387");
139 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486");
140 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486p");
141 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586");
142 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586p");
143 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686");
144 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686p");
145 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".k3d");
146 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".mmx");
147 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".xmm");
149 // Scope directives
150 // comm
151 // externdef
153 // Segment directives
154 // .alpha (32-bit only, order segments alphabetically)
155 // .dosseg (32-bit only, order segments in DOS convention)
156 // .seq (32-bit only, order segments sequentially)
157 addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegmentEnd>("ends");
158 // group (32-bit only)
159 addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegment>("segment");
161 // Simplified segment directives
162 addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(".code");
163 // .const
164 addDirectiveHandler<
165 &COFFMasmParser::ParseSectionDirectiveInitializedData>(".data");
166 addDirectiveHandler<
167 &COFFMasmParser::ParseSectionDirectiveUninitializedData>(".data?");
168 // .exit
169 // .fardata
170 // .fardata?
171 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".model");
172 // .stack
173 // .startup
175 // String directives, written <name> <directive> <params>
176 // catstr (equivalent to <name> TEXTEQU <params>)
177 // instr (equivalent to <name> = @InStr(<params>))
178 // sizestr (equivalent to <name> = @SizeStr(<params>))
179 // substr (equivalent to <name> TEXTEQU @SubStr(<params>))
181 // Structure and record directives
182 // record
183 // typedef
186 bool ParseSectionDirectiveCode(StringRef, SMLoc) {
187 return ParseSectionSwitch(".text",
188 COFF::IMAGE_SCN_CNT_CODE
189 | COFF::IMAGE_SCN_MEM_EXECUTE
190 | COFF::IMAGE_SCN_MEM_READ,
191 SectionKind::getText());
194 bool ParseSectionDirectiveInitializedData(StringRef, SMLoc) {
195 return ParseSectionSwitch(".data",
196 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
197 | COFF::IMAGE_SCN_MEM_READ
198 | COFF::IMAGE_SCN_MEM_WRITE,
199 SectionKind::getData());
202 bool ParseSectionDirectiveUninitializedData(StringRef, SMLoc) {
203 return ParseSectionSwitch(".bss",
204 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
205 | COFF::IMAGE_SCN_MEM_READ
206 | COFF::IMAGE_SCN_MEM_WRITE,
207 SectionKind::getBSS());
210 /// Stack of active procedure definitions.
211 SmallVector<StringRef, 1> CurrentProcedures;
212 SmallVector<bool, 1> CurrentProceduresFramed;
214 public:
215 COFFMasmParser() = default;
218 } // end anonymous namespace.
220 bool COFFMasmParser::ParseSectionSwitch(StringRef SectionName,
221 unsigned Characteristics,
222 SectionKind Kind) {
223 return ParseSectionSwitch(SectionName, Characteristics, Kind, "",
224 (COFF::COMDATType)0, Align(16));
227 bool COFFMasmParser::ParseSectionSwitch(
228 StringRef SectionName, unsigned Characteristics, SectionKind Kind,
229 StringRef COMDATSymName, COFF::COMDATType Type, Align Alignment) {
230 if (getLexer().isNot(AsmToken::EndOfStatement))
231 return TokError("unexpected token in section switching directive");
232 Lex();
234 MCSection *Section = getContext().getCOFFSection(SectionName, Characteristics,
235 Kind, COMDATSymName, Type);
236 Section->setAlignment(Alignment);
237 getStreamer().switchSection(Section);
239 return false;
242 bool COFFMasmParser::ParseDirectiveSegment(StringRef Directive, SMLoc Loc) {
243 StringRef SegmentName;
244 if (!getLexer().is(AsmToken::Identifier))
245 return TokError("expected identifier in directive");
246 SegmentName = getTok().getIdentifier();
247 Lex();
249 StringRef SectionName = SegmentName;
250 SmallVector<char, 247> SectionNameVector;
252 StringRef Class;
253 if (SegmentName == "_TEXT" || SegmentName.starts_with("_TEXT$")) {
254 if (SegmentName.size() == 5) {
255 SectionName = ".text";
256 } else {
257 SectionName =
258 (".text$" + SegmentName.substr(6)).toStringRef(SectionNameVector);
260 Class = "CODE";
263 // Parse all options to end of statement.
264 // Alignment defaults to PARA if unspecified.
265 int64_t Alignment = 16;
266 // Default flags are used only if no characteristics are set.
267 bool DefaultCharacteristics = true;
268 unsigned Flags = 0;
269 // "obsolete" according to the documentation, but still supported.
270 bool Readonly = false;
271 while (getLexer().isNot(AsmToken::EndOfStatement)) {
272 switch (getTok().getKind()) {
273 default:
274 break;
275 case AsmToken::String: {
276 // Class identifier; overrides Kind.
277 Class = getTok().getStringContents();
278 Lex();
279 break;
281 case AsmToken::Identifier: {
282 SMLoc KeywordLoc = getTok().getLoc();
283 StringRef Keyword;
284 if (getParser().parseIdentifier(Keyword)) {
285 llvm_unreachable("failed to parse identifier at an identifier token");
287 if (Keyword.equals_insensitive("byte")) {
288 Alignment = 1;
289 } else if (Keyword.equals_insensitive("word")) {
290 Alignment = 2;
291 } else if (Keyword.equals_insensitive("dword")) {
292 Alignment = 4;
293 } else if (Keyword.equals_insensitive("para")) {
294 Alignment = 16;
295 } else if (Keyword.equals_insensitive("page")) {
296 Alignment = 256;
297 } else if (Keyword.equals_insensitive("align")) {
298 if (getParser().parseToken(AsmToken::LParen) ||
299 getParser().parseIntToken(Alignment,
300 "Expected integer alignment") ||
301 getParser().parseToken(AsmToken::RParen)) {
302 return Error(getTok().getLoc(),
303 "Expected (n) following ALIGN in SEGMENT directive");
305 if (!isPowerOf2_64(Alignment) || Alignment > 8192) {
306 return Error(KeywordLoc,
307 "ALIGN argument must be a power of 2 from 1 to 8192");
309 } else if (Keyword.equals_insensitive("alias")) {
310 if (getParser().parseToken(AsmToken::LParen) ||
311 !getTok().is(AsmToken::String))
312 return Error(
313 getTok().getLoc(),
314 "Expected (string) following ALIAS in SEGMENT directive");
315 SectionName = getTok().getStringContents();
316 Lex();
317 if (getParser().parseToken(AsmToken::RParen))
318 return Error(
319 getTok().getLoc(),
320 "Expected (string) following ALIAS in SEGMENT directive");
321 } else if (Keyword.equals_insensitive("readonly")) {
322 Readonly = true;
323 } else {
324 unsigned Characteristic =
325 StringSwitch<unsigned>(Keyword)
326 .CaseLower("info", COFF::IMAGE_SCN_LNK_INFO)
327 .CaseLower("read", COFF::IMAGE_SCN_MEM_READ)
328 .CaseLower("write", COFF::IMAGE_SCN_MEM_WRITE)
329 .CaseLower("execute", COFF::IMAGE_SCN_MEM_EXECUTE)
330 .CaseLower("shared", COFF::IMAGE_SCN_MEM_SHARED)
331 .CaseLower("nopage", COFF::IMAGE_SCN_MEM_NOT_PAGED)
332 .CaseLower("nocache", COFF::IMAGE_SCN_MEM_NOT_CACHED)
333 .CaseLower("discard", COFF::IMAGE_SCN_MEM_DISCARDABLE)
334 .Default(-1);
335 if (Characteristic == static_cast<unsigned>(-1)) {
336 return Error(KeywordLoc,
337 "Expected characteristic in SEGMENT directive; found '" +
338 Keyword + "'");
340 Flags |= Characteristic;
341 DefaultCharacteristics = false;
347 SectionKind Kind = StringSwitch<SectionKind>(Class)
348 .CaseLower("data", SectionKind::getData())
349 .CaseLower("code", SectionKind::getText())
350 .CaseLower("const", SectionKind::getReadOnly())
351 .Default(SectionKind::getData());
352 if (Kind.isText()) {
353 if (DefaultCharacteristics) {
354 Flags |= COFF::IMAGE_SCN_MEM_EXECUTE | COFF::IMAGE_SCN_MEM_READ;
356 Flags |= COFF::IMAGE_SCN_CNT_CODE;
357 } else {
358 if (DefaultCharacteristics) {
359 Flags |= COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE;
361 Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
363 if (Readonly) {
364 Flags &= ~COFF::IMAGE_SCN_MEM_WRITE;
367 MCSection *Section = getContext().getCOFFSection(SectionName, Flags, Kind, "",
368 (COFF::COMDATType)(0));
369 if (Alignment != 0) {
370 Section->setAlignment(Align(Alignment));
372 getStreamer().switchSection(Section);
373 return false;
376 /// ParseDirectiveSegmentEnd
377 /// ::= identifier "ends"
378 bool COFFMasmParser::ParseDirectiveSegmentEnd(StringRef Directive, SMLoc Loc) {
379 StringRef SegmentName;
380 if (!getLexer().is(AsmToken::Identifier))
381 return TokError("expected identifier in directive");
382 SegmentName = getTok().getIdentifier();
384 // Ignore; no action necessary.
385 Lex();
386 return false;
389 /// ParseDirectiveIncludelib
390 /// ::= "includelib" identifier
391 bool COFFMasmParser::ParseDirectiveIncludelib(StringRef Directive, SMLoc Loc) {
392 StringRef Lib;
393 if (getParser().parseIdentifier(Lib))
394 return TokError("expected identifier in includelib directive");
396 unsigned Flags = COFF::IMAGE_SCN_MEM_PRELOAD | COFF::IMAGE_SCN_MEM_16BIT;
397 SectionKind Kind = SectionKind::getData();
398 getStreamer().pushSection();
399 getStreamer().switchSection(getContext().getCOFFSection(
400 ".drectve", Flags, Kind, "", (COFF::COMDATType)(0)));
401 getStreamer().emitBytes("/DEFAULTLIB:");
402 getStreamer().emitBytes(Lib);
403 getStreamer().emitBytes(" ");
404 getStreamer().popSection();
405 return false;
408 /// ParseDirectiveOption
409 /// ::= "option" option-list
410 bool COFFMasmParser::ParseDirectiveOption(StringRef Directive, SMLoc Loc) {
411 auto parseOption = [&]() -> bool {
412 StringRef Option;
413 if (getParser().parseIdentifier(Option))
414 return TokError("expected identifier for option name");
415 if (Option.equals_insensitive("prologue")) {
416 StringRef MacroId;
417 if (parseToken(AsmToken::Colon) || getParser().parseIdentifier(MacroId))
418 return TokError("expected :macroId after OPTION PROLOGUE");
419 if (MacroId.equals_insensitive("none")) {
420 // Since we currently don't implement prologues/epilogues, NONE is our
421 // default.
422 return false;
424 return TokError("OPTION PROLOGUE is currently unsupported");
426 if (Option.equals_insensitive("epilogue")) {
427 StringRef MacroId;
428 if (parseToken(AsmToken::Colon) || getParser().parseIdentifier(MacroId))
429 return TokError("expected :macroId after OPTION EPILOGUE");
430 if (MacroId.equals_insensitive("none")) {
431 // Since we currently don't implement prologues/epilogues, NONE is our
432 // default.
433 return false;
435 return TokError("OPTION EPILOGUE is currently unsupported");
437 return TokError("OPTION '" + Option + "' is currently unsupported");
440 if (parseMany(parseOption))
441 return addErrorSuffix(" in OPTION directive");
442 return false;
445 /// ParseDirectiveProc
446 /// TODO(epastor): Implement parameters and other attributes.
447 /// ::= label "proc" [[distance]]
448 /// statements
449 /// label "endproc"
450 bool COFFMasmParser::ParseDirectiveProc(StringRef Directive, SMLoc Loc) {
451 StringRef Label;
452 if (getParser().parseIdentifier(Label))
453 return Error(Loc, "expected identifier for procedure");
454 if (getLexer().is(AsmToken::Identifier)) {
455 StringRef nextVal = getTok().getString();
456 SMLoc nextLoc = getTok().getLoc();
457 if (nextVal.equals_insensitive("far")) {
458 // TODO(epastor): Handle far procedure definitions.
459 Lex();
460 return Error(nextLoc, "far procedure definitions not yet supported");
461 } else if (nextVal.equals_insensitive("near")) {
462 Lex();
463 nextVal = getTok().getString();
464 nextLoc = getTok().getLoc();
467 MCSymbolCOFF *Sym = cast<MCSymbolCOFF>(getContext().getOrCreateSymbol(Label));
469 // Define symbol as simple external function
470 Sym->setExternal(true);
471 Sym->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT);
473 bool Framed = false;
474 if (getLexer().is(AsmToken::Identifier) &&
475 getTok().getString().equals_insensitive("frame")) {
476 Lex();
477 Framed = true;
478 getStreamer().emitWinCFIStartProc(Sym, Loc);
480 getStreamer().emitLabel(Sym, Loc);
482 CurrentProcedures.push_back(Label);
483 CurrentProceduresFramed.push_back(Framed);
484 return false;
486 bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
487 StringRef Label;
488 SMLoc LabelLoc = getTok().getLoc();
489 if (getParser().parseIdentifier(Label))
490 return Error(LabelLoc, "expected identifier for procedure end");
492 if (CurrentProcedures.empty())
493 return Error(Loc, "endp outside of procedure block");
494 else if (!CurrentProcedures.back().equals_insensitive(Label))
495 return Error(LabelLoc, "endp does not match current procedure '" +
496 CurrentProcedures.back() + "'");
498 if (CurrentProceduresFramed.back()) {
499 getStreamer().emitWinCFIEndProc(Loc);
501 CurrentProcedures.pop_back();
502 CurrentProceduresFramed.pop_back();
503 return false;
506 bool COFFMasmParser::ParseDirectiveAlias(StringRef Directive, SMLoc Loc) {
507 std::string AliasName, ActualName;
508 if (getTok().isNot(AsmToken::Less) ||
509 getParser().parseAngleBracketString(AliasName))
510 return Error(getTok().getLoc(), "expected <aliasName>");
511 if (getParser().parseToken(AsmToken::Equal))
512 return addErrorSuffix(" in " + Directive + " directive");
513 if (getTok().isNot(AsmToken::Less) ||
514 getParser().parseAngleBracketString(ActualName))
515 return Error(getTok().getLoc(), "expected <actualName>");
517 MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
518 MCSymbol *Actual = getContext().getOrCreateSymbol(ActualName);
520 getStreamer().emitWeakReference(Alias, Actual);
522 return false;
525 bool COFFMasmParser::ParseSEHDirectiveAllocStack(StringRef Directive,
526 SMLoc Loc) {
527 int64_t Size;
528 SMLoc SizeLoc = getTok().getLoc();
529 if (getParser().parseAbsoluteExpression(Size))
530 return Error(SizeLoc, "expected integer size");
531 if (Size % 8 != 0)
532 return Error(SizeLoc, "stack size must be a multiple of 8");
533 getStreamer().emitWinCFIAllocStack(static_cast<unsigned>(Size), Loc);
534 return false;
537 bool COFFMasmParser::ParseSEHDirectiveEndProlog(StringRef Directive,
538 SMLoc Loc) {
539 getStreamer().emitWinCFIEndProlog(Loc);
540 return false;
543 namespace llvm {
545 MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; }
547 } // end namespace llvm