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