cc356c7a1748482c19b41baa61e24e5fc60f8b20
[oota-llvm.git] / lib / MC / MCParser / COFFAsmParser.cpp
1 //===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
11 #include "llvm/ADT/StringSwitch.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/MC/MCAsmInfo.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCExpr.h"
16 #include "llvm/MC/MCParser/MCAsmLexer.h"
17 #include "llvm/MC/MCRegisterInfo.h"
18 #include "llvm/MC/MCSectionCOFF.h"
19 #include "llvm/MC/MCStreamer.h"
20 #include "llvm/MC/MCTargetAsmParser.h"
21 #include "llvm/Support/COFF.h"
22 using namespace llvm;
23
24 namespace {
25
26 class COFFAsmParser : public MCAsmParserExtension {
27   template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
28   void addDirectiveHandler(StringRef Directive) {
29     MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
30         this, HandleDirective<COFFAsmParser, HandlerMethod>);
31     getParser().addDirectiveHandler(Directive, Handler);
32   }
33
34   bool ParseSectionSwitch(StringRef Section,
35                           unsigned Characteristics,
36                           SectionKind Kind);
37
38   bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
39                           SectionKind Kind, StringRef COMDATSymName,
40                           COFF::COMDATType Type, const MCSectionCOFF *Assoc);
41
42   bool ParseSectionName(StringRef &SectionName);
43   bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags);
44
45   virtual void Initialize(MCAsmParser &Parser) {
46     // Call the base implementation.
47     MCAsmParserExtension::Initialize(Parser);
48
49     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
50     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
51     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
52     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
53     addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
54     addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
55     addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
56     addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
57     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
58     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
59     addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
60
61     // Win64 EH directives.
62     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
63                                                                    ".seh_proc");
64     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
65                                                                 ".seh_endproc");
66     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
67                                                            ".seh_startchained");
68     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
69                                                              ".seh_endchained");
70     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
71                                                                 ".seh_handler");
72     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
73                                                             ".seh_handlerdata");
74     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
75                                                                 ".seh_pushreg");
76     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
77                                                                ".seh_setframe");
78     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
79                                                              ".seh_stackalloc");
80     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
81                                                                 ".seh_savereg");
82     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
83                                                                 ".seh_savexmm");
84     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
85                                                               ".seh_pushframe");
86     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
87                                                             ".seh_endprologue");
88     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
89   }
90
91   bool ParseSectionDirectiveText(StringRef, SMLoc) {
92     return ParseSectionSwitch(".text",
93                               COFF::IMAGE_SCN_CNT_CODE
94                             | COFF::IMAGE_SCN_MEM_EXECUTE
95                             | COFF::IMAGE_SCN_MEM_READ,
96                               SectionKind::getText());
97   }
98   bool ParseSectionDirectiveData(StringRef, SMLoc) {
99     return ParseSectionSwitch(".data",
100                               COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
101                             | COFF::IMAGE_SCN_MEM_READ
102                             | COFF::IMAGE_SCN_MEM_WRITE,
103                               SectionKind::getDataRel());
104   }
105   bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
106     return ParseSectionSwitch(".bss",
107                               COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
108                             | COFF::IMAGE_SCN_MEM_READ
109                             | COFF::IMAGE_SCN_MEM_WRITE,
110                               SectionKind::getBSS());
111   }
112
113   bool ParseDirectiveSection(StringRef, SMLoc);
114   bool ParseDirectiveDef(StringRef, SMLoc);
115   bool ParseDirectiveScl(StringRef, SMLoc);
116   bool ParseDirectiveType(StringRef, SMLoc);
117   bool ParseDirectiveEndef(StringRef, SMLoc);
118   bool ParseDirectiveSecRel32(StringRef, SMLoc);
119   bool ParseDirectiveSecIdx(StringRef, SMLoc);
120   bool parseCOMDATTypeAndAssoc(COFF::COMDATType &Type,
121                                const MCSectionCOFF *&Assoc);
122   bool ParseDirectiveLinkOnce(StringRef, SMLoc);
123
124   // Win64 EH directives.
125   bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
126   bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
127   bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
128   bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
129   bool ParseSEHDirectiveHandler(StringRef, SMLoc);
130   bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
131   bool ParseSEHDirectivePushReg(StringRef, SMLoc);
132   bool ParseSEHDirectiveSetFrame(StringRef, SMLoc);
133   bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
134   bool ParseSEHDirectiveSaveReg(StringRef, SMLoc);
135   bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc);
136   bool ParseSEHDirectivePushFrame(StringRef, SMLoc);
137   bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
138
139   bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
140   bool ParseSEHRegisterNumber(unsigned &RegNo);
141   bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
142 public:
143   COFFAsmParser() {}
144 };
145
146 } // end annonomous namespace.
147
148 static SectionKind computeSectionKind(unsigned Flags) {
149   if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
150     return SectionKind::getText();
151   if (Flags & COFF::IMAGE_SCN_MEM_READ &&
152       (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
153     return SectionKind::getReadOnly();
154   return SectionKind::getDataRel();
155 }
156
157 bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) {
158   enum {
159     None      = 0,
160     Alloc     = 1 << 0,
161     Code      = 1 << 1,
162     Load      = 1 << 2,
163     InitData  = 1 << 3,
164     Shared    = 1 << 4,
165     NoLoad    = 1 << 5,
166     NoRead    = 1 << 6,
167     NoWrite  =  1 << 7
168   };
169
170   bool ReadOnlyRemoved = false;
171   unsigned SecFlags = None;
172
173   for (unsigned i = 0; i < FlagsString.size(); ++i) {
174     switch (FlagsString[i]) {
175     case 'a':
176       // Ignored.
177       break;
178
179     case 'b': // bss section
180       SecFlags |= Alloc;
181       if (SecFlags & InitData)
182         return TokError("conflicting section flags 'b' and 'd'.");
183       SecFlags &= ~Load;
184       break;
185
186     case 'd': // data section
187       SecFlags |= InitData;
188       if (SecFlags & Alloc)
189         return TokError("conflicting section flags 'b' and 'd'.");
190       SecFlags &= ~NoWrite;
191       if ((SecFlags & NoLoad) == 0)
192         SecFlags |= Load;
193       break;
194
195     case 'n': // section is not loaded
196       SecFlags |= NoLoad;
197       SecFlags &= ~Load;
198       break;
199
200     case 'r': // read-only
201       ReadOnlyRemoved = false;
202       SecFlags |= NoWrite;
203       if ((SecFlags & Code) == 0)
204         SecFlags |= InitData;
205       if ((SecFlags & NoLoad) == 0)
206         SecFlags |= Load;
207       break;
208
209     case 's': // shared section
210       SecFlags |= Shared | InitData;
211       SecFlags &= ~NoWrite;
212       if ((SecFlags & NoLoad) == 0)
213         SecFlags |= Load;
214       break;
215
216     case 'w': // writable
217       SecFlags &= ~NoWrite;
218       ReadOnlyRemoved = true;
219       break;
220
221     case 'x': // executable section
222       SecFlags |= Code;
223       if ((SecFlags & NoLoad) == 0)
224         SecFlags |= Load;
225       if (!ReadOnlyRemoved)
226         SecFlags |= NoWrite;
227       break;
228
229     case 'y': // not readable
230       SecFlags |= NoRead | NoWrite;
231       break;
232
233     default:
234       return TokError("unknown flag");
235     }
236   }
237
238   *Flags = 0;
239
240   if (SecFlags == None)
241     SecFlags = InitData;
242
243   if (SecFlags & Code)
244     *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
245   if (SecFlags & InitData)
246     *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
247   if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
248     *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
249   if (SecFlags & NoLoad)
250     *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
251   if ((SecFlags & NoRead) == 0)
252     *Flags |= COFF::IMAGE_SCN_MEM_READ;
253   if ((SecFlags & NoWrite) == 0)
254     *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
255   if (SecFlags & Shared)
256     *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
257
258   return false;
259 }
260
261 /// ParseDirectiveSymbolAttribute
262 ///  ::= { ".weak", ... } [ identifier ( , identifier )* ]
263 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
264   MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
265     .Case(".weak", MCSA_Weak)
266     .Default(MCSA_Invalid);
267   assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
268   if (getLexer().isNot(AsmToken::EndOfStatement)) {
269     for (;;) {
270       StringRef Name;
271
272       if (getParser().parseIdentifier(Name))
273         return TokError("expected identifier in directive");
274
275       MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
276
277       getStreamer().EmitSymbolAttribute(Sym, Attr);
278
279       if (getLexer().is(AsmToken::EndOfStatement))
280         break;
281
282       if (getLexer().isNot(AsmToken::Comma))
283         return TokError("unexpected token in directive");
284       Lex();
285     }
286   }
287
288   Lex();
289   return false;
290 }
291
292 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
293                                        unsigned Characteristics,
294                                        SectionKind Kind) {
295   return ParseSectionSwitch(Section, Characteristics, Kind, "",
296                             COFF::IMAGE_COMDAT_SELECT_ANY, 0);
297 }
298
299 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
300                                        unsigned Characteristics,
301                                        SectionKind Kind,
302                                        StringRef COMDATSymName,
303                                        COFF::COMDATType Type,
304                                        const MCSectionCOFF *Assoc) {
305   if (getLexer().isNot(AsmToken::EndOfStatement))
306     return TokError("unexpected token in section switching directive");
307   Lex();
308
309   getStreamer().SwitchSection(getContext().getCOFFSection(
310       Section, Characteristics, Kind, COMDATSymName, Type, Assoc));
311
312   return false;
313 }
314
315 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
316   if (!getLexer().is(AsmToken::Identifier))
317     return true;
318
319   SectionName = getTok().getIdentifier();
320   Lex();
321   return false;
322 }
323
324 // .section name [, "flags"] [, identifier [ identifier ], identifier]
325 //
326 // Supported flags:
327 //   a: Ignored.
328 //   b: BSS section (uninitialized data)
329 //   d: data section (initialized data)
330 //   n: Discardable section
331 //   r: Readable section
332 //   s: Shared section
333 //   w: Writable section
334 //   x: Executable section
335 //   y: Not-readable section (clears 'r')
336 //
337 // Subsections are not supported.
338 bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
339   StringRef SectionName;
340
341   if (ParseSectionName(SectionName))
342     return TokError("expected identifier in directive");
343
344   unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
345                    COFF::IMAGE_SCN_MEM_READ |
346                    COFF::IMAGE_SCN_MEM_WRITE;
347
348   if (getLexer().is(AsmToken::Comma)) {
349     Lex();
350
351     if (getLexer().isNot(AsmToken::String))
352       return TokError("expected string in directive");
353
354     StringRef FlagsStr = getTok().getStringContents();
355     Lex();
356
357     if (ParseSectionFlags(FlagsStr, &Flags))
358       return true;
359   }
360
361   COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
362   const MCSectionCOFF *Assoc = 0;
363   StringRef COMDATSymName;
364   if (getLexer().is(AsmToken::Comma)) {
365     Lex();
366
367     Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
368
369     if (parseCOMDATTypeAndAssoc(Type, Assoc))
370       return true;
371
372     if (getLexer().isNot(AsmToken::Comma))
373       return TokError("expected comma in directive");
374     Lex();
375
376     if (getParser().parseIdentifier(COMDATSymName))
377       return TokError("expected identifier in directive");
378   }
379
380   if (getLexer().isNot(AsmToken::EndOfStatement))
381     return TokError("unexpected token in directive");
382
383   SectionKind Kind = computeSectionKind(Flags);
384   ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type, Assoc);
385   return false;
386 }
387
388 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
389   StringRef SymbolName;
390
391   if (getParser().parseIdentifier(SymbolName))
392     return TokError("expected identifier in directive");
393
394   MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
395
396   getStreamer().BeginCOFFSymbolDef(Sym);
397
398   Lex();
399   return false;
400 }
401
402 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
403   int64_t SymbolStorageClass;
404   if (getParser().parseAbsoluteExpression(SymbolStorageClass))
405     return true;
406
407   if (getLexer().isNot(AsmToken::EndOfStatement))
408     return TokError("unexpected token in directive");
409
410   Lex();
411   getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
412   return false;
413 }
414
415 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
416   int64_t Type;
417   if (getParser().parseAbsoluteExpression(Type))
418     return true;
419
420   if (getLexer().isNot(AsmToken::EndOfStatement))
421     return TokError("unexpected token in directive");
422
423   Lex();
424   getStreamer().EmitCOFFSymbolType(Type);
425   return false;
426 }
427
428 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
429   Lex();
430   getStreamer().EndCOFFSymbolDef();
431   return false;
432 }
433
434 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
435   StringRef SymbolID;
436   if (getParser().parseIdentifier(SymbolID))
437     return TokError("expected identifier in directive");
438
439   if (getLexer().isNot(AsmToken::EndOfStatement))
440     return TokError("unexpected token in directive");
441
442   MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
443
444   Lex();
445   getStreamer().EmitCOFFSecRel32(Symbol);
446   return false;
447 }
448
449 bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
450   StringRef SymbolID;
451   if (getParser().parseIdentifier(SymbolID))
452     return TokError("expected identifier in directive");
453
454   if (getLexer().isNot(AsmToken::EndOfStatement))
455     return TokError("unexpected token in directive");
456
457   MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
458
459   Lex();
460   getStreamer().EmitCOFFSectionIndex(Symbol);
461   return false;
462 }
463
464 /// ::= [ identifier [ identifier ] ]
465 bool COFFAsmParser::parseCOMDATTypeAndAssoc(COFF::COMDATType &Type,
466                                             const MCSectionCOFF *&Assoc) {
467   StringRef TypeId = getTok().getIdentifier();
468
469   Type = StringSwitch<COFF::COMDATType>(TypeId)
470     .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
471     .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
472     .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
473     .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
474     .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
475     .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
476     .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
477     .Default((COFF::COMDATType)0);
478
479   if (Type == 0)
480     return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
481
482   Lex();
483
484   if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
485     SMLoc Loc = getTok().getLoc();
486     StringRef AssocName;
487     if (ParseSectionName(AssocName))
488       return TokError("expected associated section name");
489
490     Assoc = static_cast<const MCSectionCOFF*>(
491                                         getContext().getCOFFSection(AssocName));
492     if (!Assoc)
493       return Error(Loc, "cannot associate unknown section '" + AssocName + "'");
494     if (!(Assoc->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT))
495       return Error(Loc, "associated section must be a COMDAT section");
496     if (Assoc->getSelection() == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
497       return Error(Loc, "associated section cannot be itself associative");
498   }
499
500   return false;
501 }
502
503 /// ParseDirectiveLinkOnce
504 ///  ::= .linkonce [ identifier [ identifier ] ]
505 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
506   COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
507   const MCSectionCOFF *Assoc = 0;
508   if (getLexer().is(AsmToken::Identifier))
509     if (parseCOMDATTypeAndAssoc(Type, Assoc))
510       return true;
511
512   const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>(
513                                        getStreamer().getCurrentSection().first);
514
515
516   if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
517     if (Assoc == Current)
518       return Error(Loc, "cannot associate a section with itself");
519   }
520
521   if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
522     return Error(Loc, Twine("section '") + Current->getSectionName() +
523                                                        "' is already linkonce");
524
525   Current->setSelection(Type, Assoc);
526
527   if (getLexer().isNot(AsmToken::EndOfStatement))
528     return TokError("unexpected token in directive");
529
530   return false;
531 }
532
533 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
534   StringRef SymbolID;
535   if (getParser().parseIdentifier(SymbolID))
536     return true;
537
538   if (getLexer().isNot(AsmToken::EndOfStatement))
539     return TokError("unexpected token in directive");
540
541   MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
542
543   Lex();
544   getStreamer().EmitWin64EHStartProc(Symbol);
545   return false;
546 }
547
548 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
549   Lex();
550   getStreamer().EmitWin64EHEndProc();
551   return false;
552 }
553
554 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
555   Lex();
556   getStreamer().EmitWin64EHStartChained();
557   return false;
558 }
559
560 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
561   Lex();
562   getStreamer().EmitWin64EHEndChained();
563   return false;
564 }
565
566 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
567   StringRef SymbolID;
568   if (getParser().parseIdentifier(SymbolID))
569     return true;
570
571   if (getLexer().isNot(AsmToken::Comma))
572     return TokError("you must specify one or both of @unwind or @except");
573   Lex();
574   bool unwind = false, except = false;
575   if (ParseAtUnwindOrAtExcept(unwind, except))
576     return true;
577   if (getLexer().is(AsmToken::Comma)) {
578     Lex();
579     if (ParseAtUnwindOrAtExcept(unwind, except))
580       return true;
581   }
582   if (getLexer().isNot(AsmToken::EndOfStatement))
583     return TokError("unexpected token in directive");
584
585   MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
586
587   Lex();
588   getStreamer().EmitWin64EHHandler(handler, unwind, except);
589   return false;
590 }
591
592 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
593   Lex();
594   getStreamer().EmitWin64EHHandlerData();
595   return false;
596 }
597
598 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
599   unsigned Reg;
600   if (ParseSEHRegisterNumber(Reg))
601     return true;
602
603   if (getLexer().isNot(AsmToken::EndOfStatement))
604     return TokError("unexpected token in directive");
605
606   Lex();
607   getStreamer().EmitWin64EHPushReg(Reg);
608   return false;
609 }
610
611 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
612   unsigned Reg;
613   int64_t Off;
614   if (ParseSEHRegisterNumber(Reg))
615     return true;
616   if (getLexer().isNot(AsmToken::Comma))
617     return TokError("you must specify a stack pointer offset");
618
619   Lex();
620   SMLoc startLoc = getLexer().getLoc();
621   if (getParser().parseAbsoluteExpression(Off))
622     return true;
623
624   if (Off & 0x0F)
625     return Error(startLoc, "offset is not a multiple of 16");
626
627   if (getLexer().isNot(AsmToken::EndOfStatement))
628     return TokError("unexpected token in directive");
629
630   Lex();
631   getStreamer().EmitWin64EHSetFrame(Reg, Off);
632   return false;
633 }
634
635 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
636   int64_t Size;
637   SMLoc startLoc = getLexer().getLoc();
638   if (getParser().parseAbsoluteExpression(Size))
639     return true;
640
641   if (Size & 7)
642     return Error(startLoc, "size is not a multiple of 8");
643
644   if (getLexer().isNot(AsmToken::EndOfStatement))
645     return TokError("unexpected token in directive");
646
647   Lex();
648   getStreamer().EmitWin64EHAllocStack(Size);
649   return false;
650 }
651
652 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
653   unsigned Reg;
654   int64_t Off;
655   if (ParseSEHRegisterNumber(Reg))
656     return true;
657   if (getLexer().isNot(AsmToken::Comma))
658     return TokError("you must specify an offset on the stack");
659
660   Lex();
661   SMLoc startLoc = getLexer().getLoc();
662   if (getParser().parseAbsoluteExpression(Off))
663     return true;
664
665   if (Off & 7)
666     return Error(startLoc, "size is not a multiple of 8");
667
668   if (getLexer().isNot(AsmToken::EndOfStatement))
669     return TokError("unexpected token in directive");
670
671   Lex();
672   // FIXME: Err on %xmm* registers
673   getStreamer().EmitWin64EHSaveReg(Reg, Off);
674   return false;
675 }
676
677 // FIXME: This method is inherently x86-specific. It should really be in the
678 // x86 backend.
679 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
680   unsigned Reg;
681   int64_t Off;
682   if (ParseSEHRegisterNumber(Reg))
683     return true;
684   if (getLexer().isNot(AsmToken::Comma))
685     return TokError("you must specify an offset on the stack");
686
687   Lex();
688   SMLoc startLoc = getLexer().getLoc();
689   if (getParser().parseAbsoluteExpression(Off))
690     return true;
691
692   if (getLexer().isNot(AsmToken::EndOfStatement))
693     return TokError("unexpected token in directive");
694
695   if (Off & 0x0F)
696     return Error(startLoc, "offset is not a multiple of 16");
697
698   Lex();
699   // FIXME: Err on non-%xmm* registers
700   getStreamer().EmitWin64EHSaveXMM(Reg, Off);
701   return false;
702 }
703
704 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
705   bool Code = false;
706   StringRef CodeID;
707   if (getLexer().is(AsmToken::At)) {
708     SMLoc startLoc = getLexer().getLoc();
709     Lex();
710     if (!getParser().parseIdentifier(CodeID)) {
711       if (CodeID != "code")
712         return Error(startLoc, "expected @code");
713       Code = true;
714     }
715   }
716
717   if (getLexer().isNot(AsmToken::EndOfStatement))
718     return TokError("unexpected token in directive");
719
720   Lex();
721   getStreamer().EmitWin64EHPushFrame(Code);
722   return false;
723 }
724
725 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
726   Lex();
727   getStreamer().EmitWin64EHEndProlog();
728   return false;
729 }
730
731 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
732   StringRef identifier;
733   if (getLexer().isNot(AsmToken::At))
734     return TokError("a handler attribute must begin with '@'");
735   SMLoc startLoc = getLexer().getLoc();
736   Lex();
737   if (getParser().parseIdentifier(identifier))
738     return Error(startLoc, "expected @unwind or @except");
739   if (identifier == "unwind")
740     unwind = true;
741   else if (identifier == "except")
742     except = true;
743   else
744     return Error(startLoc, "expected @unwind or @except");
745   return false;
746 }
747
748 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
749   SMLoc startLoc = getLexer().getLoc();
750   if (getLexer().is(AsmToken::Percent)) {
751     const MCRegisterInfo *MRI = getContext().getRegisterInfo();
752     SMLoc endLoc;
753     unsigned LLVMRegNo;
754     if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
755       return true;
756
757 #if 0
758     // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
759     // violation so this validation code is disabled.
760
761     // Check that this is a non-volatile register.
762     const unsigned *NVRegs = TAI.getCalleeSavedRegs();
763     unsigned i;
764     for (i = 0; NVRegs[i] != 0; ++i)
765       if (NVRegs[i] == LLVMRegNo)
766         break;
767     if (NVRegs[i] == 0)
768       return Error(startLoc, "expected non-volatile register");
769 #endif
770
771     int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
772     if (SEHRegNo < 0)
773       return Error(startLoc,"register can't be represented in SEH unwind info");
774     RegNo = SEHRegNo;
775   }
776   else {
777     int64_t n;
778     if (getParser().parseAbsoluteExpression(n))
779       return true;
780     if (n > 15)
781       return Error(startLoc, "register number is too high");
782     RegNo = n;
783   }
784
785   return false;
786 }
787
788 namespace llvm {
789
790 MCAsmParserExtension *createCOFFAsmParser() {
791   return new COFFAsmParser;
792 }
793
794 }