diff options
Diffstat (limited to 'contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp')
-rw-r--r-- | contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp | 777 |
1 files changed, 777 insertions, 0 deletions
diff --git a/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp new file mode 100644 index 000000000000..d8343a3eea1b --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -0,0 +1,777 @@ +//===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/COFF.h" +using namespace llvm; + +namespace { + +class COFFAsmParser : public MCAsmParserExtension { + template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)> + void addDirectiveHandler(StringRef Directive) { + MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( + this, HandleDirective<COFFAsmParser, HandlerMethod>); + getParser().addDirectiveHandler(Directive, Handler); + } + + bool ParseSectionSwitch(StringRef Section, + unsigned Characteristics, + SectionKind Kind); + + bool ParseSectionSwitch(StringRef Section, unsigned Characteristics, + SectionKind Kind, StringRef COMDATSymName, + COFF::COMDATType Type, const MCSectionCOFF *Assoc); + + bool ParseSectionName(StringRef &SectionName); + bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags); + + virtual void Initialize(MCAsmParser &Parser) { + // Call the base implementation. + MCAsmParserExtension::Initialize(Parser); + + addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text"); + addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data"); + addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); + + // Win64 EH directives. + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( + ".seh_proc"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>( + ".seh_endproc"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>( + ".seh_startchained"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>( + ".seh_endchained"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>( + ".seh_handler"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>( + ".seh_handlerdata"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>( + ".seh_pushreg"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>( + ".seh_setframe"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>( + ".seh_stackalloc"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>( + ".seh_savereg"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>( + ".seh_savexmm"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>( + ".seh_pushframe"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>( + ".seh_endprologue"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); + } + + bool ParseSectionDirectiveText(StringRef, SMLoc) { + return ParseSectionSwitch(".text", + COFF::IMAGE_SCN_CNT_CODE + | COFF::IMAGE_SCN_MEM_EXECUTE + | COFF::IMAGE_SCN_MEM_READ, + SectionKind::getText()); + } + bool ParseSectionDirectiveData(StringRef, SMLoc) { + return ParseSectionSwitch(".data", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); + } + bool ParseSectionDirectiveBSS(StringRef, SMLoc) { + return ParseSectionSwitch(".bss", + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getBSS()); + } + + bool ParseDirectiveSection(StringRef, SMLoc); + bool ParseDirectiveDef(StringRef, SMLoc); + bool ParseDirectiveScl(StringRef, SMLoc); + bool ParseDirectiveType(StringRef, SMLoc); + bool ParseDirectiveEndef(StringRef, SMLoc); + bool ParseDirectiveSecRel32(StringRef, SMLoc); + bool parseCOMDATTypeAndAssoc(COFF::COMDATType &Type, + const MCSectionCOFF *&Assoc); + bool ParseDirectiveLinkOnce(StringRef, SMLoc); + + // Win64 EH directives. + bool ParseSEHDirectiveStartProc(StringRef, SMLoc); + bool ParseSEHDirectiveEndProc(StringRef, SMLoc); + bool ParseSEHDirectiveStartChained(StringRef, SMLoc); + bool ParseSEHDirectiveEndChained(StringRef, SMLoc); + bool ParseSEHDirectiveHandler(StringRef, SMLoc); + bool ParseSEHDirectiveHandlerData(StringRef, SMLoc); + bool ParseSEHDirectivePushReg(StringRef, SMLoc); + bool ParseSEHDirectiveSetFrame(StringRef, SMLoc); + bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); + bool ParseSEHDirectiveSaveReg(StringRef, SMLoc); + bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc); + bool ParseSEHDirectivePushFrame(StringRef, SMLoc); + bool ParseSEHDirectiveEndProlog(StringRef, SMLoc); + + bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except); + bool ParseSEHRegisterNumber(unsigned &RegNo); + bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc); +public: + COFFAsmParser() {} +}; + +} // end annonomous namespace. + +static SectionKind computeSectionKind(unsigned Flags) { + if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) + return SectionKind::getText(); + if (Flags & COFF::IMAGE_SCN_MEM_READ && + (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0) + return SectionKind::getReadOnly(); + return SectionKind::getDataRel(); +} + +bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) { + enum { + None = 0, + Alloc = 1 << 0, + Code = 1 << 1, + Load = 1 << 2, + InitData = 1 << 3, + Shared = 1 << 4, + NoLoad = 1 << 5, + NoRead = 1 << 6, + NoWrite = 1 << 7 + }; + + bool ReadOnlyRemoved = false; + unsigned SecFlags = None; + + for (unsigned i = 0; i < FlagsString.size(); ++i) { + switch (FlagsString[i]) { + case 'a': + // Ignored. + break; + + case 'b': // bss section + SecFlags |= Alloc; + if (SecFlags & InitData) + return TokError("conflicting section flags 'b' and 'd'."); + SecFlags &= ~Load; + break; + + case 'd': // data section + SecFlags |= InitData; + if (SecFlags & Alloc) + return TokError("conflicting section flags 'b' and 'd'."); + SecFlags &= ~NoWrite; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + break; + + case 'n': // section is not loaded + SecFlags |= NoLoad; + SecFlags &= ~Load; + break; + + case 'r': // read-only + ReadOnlyRemoved = false; + SecFlags |= NoWrite; + if ((SecFlags & Code) == 0) + SecFlags |= InitData; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + break; + + case 's': // shared section + SecFlags |= Shared | InitData; + SecFlags &= ~NoWrite; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + break; + + case 'w': // writable + SecFlags &= ~NoWrite; + ReadOnlyRemoved = true; + break; + + case 'x': // executable section + SecFlags |= Code; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + if (!ReadOnlyRemoved) + SecFlags |= NoWrite; + break; + + case 'y': // not readable + SecFlags |= NoRead | NoWrite; + break; + + default: + return TokError("unknown flag"); + } + } + + *Flags = 0; + + if (SecFlags == None) + SecFlags = InitData; + + if (SecFlags & Code) + *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE; + if (SecFlags & InitData) + *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; + if ((SecFlags & Alloc) && (SecFlags & Load) == 0) + *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; + if (SecFlags & NoLoad) + *Flags |= COFF::IMAGE_SCN_LNK_REMOVE; + if ((SecFlags & NoRead) == 0) + *Flags |= COFF::IMAGE_SCN_MEM_READ; + if ((SecFlags & NoWrite) == 0) + *Flags |= COFF::IMAGE_SCN_MEM_WRITE; + if (SecFlags & Shared) + *Flags |= COFF::IMAGE_SCN_MEM_SHARED; + + return false; +} + +/// ParseDirectiveSymbolAttribute +/// ::= { ".weak", ... } [ identifier ( , identifier )* ] +bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { + MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) + .Case(".weak", MCSA_Weak) + .Default(MCSA_Invalid); + assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + for (;;) { + StringRef Name; + + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + + getStreamer().EmitSymbolAttribute(Sym, Attr); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + + Lex(); + return false; +} + +bool COFFAsmParser::ParseSectionSwitch(StringRef Section, + unsigned Characteristics, + SectionKind Kind) { + return ParseSectionSwitch(Section, Characteristics, Kind, "", + COFF::IMAGE_COMDAT_SELECT_ANY, 0); +} + +bool COFFAsmParser::ParseSectionSwitch(StringRef Section, + unsigned Characteristics, + SectionKind Kind, + StringRef COMDATSymName, + COFF::COMDATType Type, + const MCSectionCOFF *Assoc) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in section switching directive"); + Lex(); + + getStreamer().SwitchSection(getContext().getCOFFSection( + Section, Characteristics, Kind, COMDATSymName, Type, Assoc)); + + return false; +} + +bool COFFAsmParser::ParseSectionName(StringRef &SectionName) { + if (!getLexer().is(AsmToken::Identifier)) + return true; + + SectionName = getTok().getIdentifier(); + Lex(); + return false; +} + +// .section name [, "flags"] [, identifier [ identifier ], identifier] +// +// Supported flags: +// a: Ignored. +// b: BSS section (uninitialized data) +// d: data section (initialized data) +// n: Discardable section +// r: Readable section +// s: Shared section +// w: Writable section +// x: Executable section +// y: Not-readable section (clears 'r') +// +// Subsections are not supported. +bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { + StringRef SectionName; + + if (ParseSectionName(SectionName)) + return TokError("expected identifier in directive"); + + unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE; + + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in directive"); + + StringRef FlagsStr = getTok().getStringContents(); + Lex(); + + if (ParseSectionFlags(FlagsStr, &Flags)) + return true; + } + + COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; + const MCSectionCOFF *Assoc = 0; + StringRef COMDATSymName; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + Flags |= COFF::IMAGE_SCN_LNK_COMDAT; + + if (parseCOMDATTypeAndAssoc(Type, Assoc)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected comma in directive"); + Lex(); + + if (getParser().parseIdentifier(COMDATSymName)) + return TokError("expected identifier in directive"); + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + SectionKind Kind = computeSectionKind(Flags); + ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type, Assoc); + return false; +} + +bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) { + StringRef SymbolName; + + if (getParser().parseIdentifier(SymbolName)) + return TokError("expected identifier in directive"); + + MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName); + + getStreamer().BeginCOFFSymbolDef(Sym); + + Lex(); + return false; +} + +bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) { + int64_t SymbolStorageClass; + if (getParser().parseAbsoluteExpression(SymbolStorageClass)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass); + return false; +} + +bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) { + int64_t Type; + if (getParser().parseAbsoluteExpression(Type)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitCOFFSymbolType(Type); + return false; +} + +bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) { + Lex(); + getStreamer().EndCOFFSymbolDef(); + return false; +} + +bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitCOFFSecRel32(Symbol); + return false; +} + +/// ::= [ identifier [ identifier ] ] +bool COFFAsmParser::parseCOMDATTypeAndAssoc(COFF::COMDATType &Type, + const MCSectionCOFF *&Assoc) { + StringRef TypeId = getTok().getIdentifier(); + + Type = StringSwitch<COFF::COMDATType>(TypeId) + .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) + .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY) + .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE) + .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH) + .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) + .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST) + .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST) + .Default((COFF::COMDATType)0); + + if (Type == 0) + return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'")); + + Lex(); + + if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + SMLoc Loc = getTok().getLoc(); + StringRef AssocName; + if (ParseSectionName(AssocName)) + return TokError("expected associated section name"); + + Assoc = static_cast<const MCSectionCOFF*>( + getContext().getCOFFSection(AssocName)); + if (!Assoc) + return Error(Loc, "cannot associate unknown section '" + AssocName + "'"); + if (!(Assoc->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)) + return Error(Loc, "associated section must be a COMDAT section"); + if (Assoc->getSelection() == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) + return Error(Loc, "associated section cannot be itself associative"); + } + + return false; +} + +/// ParseDirectiveLinkOnce +/// ::= .linkonce [ identifier [ identifier ] ] +bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { + COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; + const MCSectionCOFF *Assoc = 0; + if (getLexer().is(AsmToken::Identifier)) + if (parseCOMDATTypeAndAssoc(Type, Assoc)) + return true; + + const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>( + getStreamer().getCurrentSection().first); + + + if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + if (Assoc == Current) + return Error(Loc, "cannot associate a section with itself"); + } + + if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) + return Error(Loc, Twine("section '") + Current->getSectionName() + + "' is already linkonce"); + + Current->setSelection(Type, Assoc); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitWin64EHStartProc(Symbol); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) { + Lex(); + getStreamer().EmitWin64EHEndProc(); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) { + Lex(); + getStreamer().EmitWin64EHStartChained(); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) { + Lex(); + getStreamer().EmitWin64EHEndChained(); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("you must specify one or both of @unwind or @except"); + Lex(); + bool unwind = false, except = false; + if (ParseAtUnwindOrAtExcept(unwind, except)) + return true; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + if (ParseAtUnwindOrAtExcept(unwind, except)) + return true; + } + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitWin64EHHandler(handler, unwind, except); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) { + Lex(); + getStreamer().EmitWin64EHHandlerData(); + return false; +} + +bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) { + unsigned Reg; + if (ParseSEHRegisterNumber(Reg)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitWin64EHPushReg(Reg); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) { + unsigned Reg; + int64_t Off; + if (ParseSEHRegisterNumber(Reg)) + return true; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("you must specify a stack pointer offset"); + + Lex(); + SMLoc startLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Off)) + return true; + + if (Off & 0x0F) + return Error(startLoc, "offset is not a multiple of 16"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitWin64EHSetFrame(Reg, Off); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) { + int64_t Size; + SMLoc startLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Size)) + return true; + + if (Size & 7) + return Error(startLoc, "size is not a multiple of 8"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitWin64EHAllocStack(Size); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) { + unsigned Reg; + int64_t Off; + if (ParseSEHRegisterNumber(Reg)) + return true; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("you must specify an offset on the stack"); + + Lex(); + SMLoc startLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Off)) + return true; + + if (Off & 7) + return Error(startLoc, "size is not a multiple of 8"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + // FIXME: Err on %xmm* registers + getStreamer().EmitWin64EHSaveReg(Reg, Off); + return false; +} + +// FIXME: This method is inherently x86-specific. It should really be in the +// x86 backend. +bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) { + unsigned Reg; + int64_t Off; + if (ParseSEHRegisterNumber(Reg)) + return true; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("you must specify an offset on the stack"); + + Lex(); + SMLoc startLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Off)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + if (Off & 0x0F) + return Error(startLoc, "offset is not a multiple of 16"); + + Lex(); + // FIXME: Err on non-%xmm* registers + getStreamer().EmitWin64EHSaveXMM(Reg, Off); + return false; +} + +bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) { + bool Code = false; + StringRef CodeID; + if (getLexer().is(AsmToken::At)) { + SMLoc startLoc = getLexer().getLoc(); + Lex(); + if (!getParser().parseIdentifier(CodeID)) { + if (CodeID != "code") + return Error(startLoc, "expected @code"); + Code = true; + } + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitWin64EHPushFrame(Code); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) { + Lex(); + getStreamer().EmitWin64EHEndProlog(); + return false; +} + +bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) { + StringRef identifier; + if (getLexer().isNot(AsmToken::At)) + return TokError("a handler attribute must begin with '@'"); + SMLoc startLoc = getLexer().getLoc(); + Lex(); + if (getParser().parseIdentifier(identifier)) + return Error(startLoc, "expected @unwind or @except"); + if (identifier == "unwind") + unwind = true; + else if (identifier == "except") + except = true; + else + return Error(startLoc, "expected @unwind or @except"); + return false; +} + +bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) { + SMLoc startLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::Percent)) { + const MCRegisterInfo *MRI = getContext().getRegisterInfo(); + SMLoc endLoc; + unsigned LLVMRegNo; + if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc)) + return true; + +#if 0 + // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering + // violation so this validation code is disabled. + + // Check that this is a non-volatile register. + const unsigned *NVRegs = TAI.getCalleeSavedRegs(); + unsigned i; + for (i = 0; NVRegs[i] != 0; ++i) + if (NVRegs[i] == LLVMRegNo) + break; + if (NVRegs[i] == 0) + return Error(startLoc, "expected non-volatile register"); +#endif + + int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo); + if (SEHRegNo < 0) + return Error(startLoc,"register can't be represented in SEH unwind info"); + RegNo = SEHRegNo; + } + else { + int64_t n; + if (getParser().parseAbsoluteExpression(n)) + return true; + if (n > 15) + return Error(startLoc, "register number is too high"); + RegNo = n; + } + + return false; +} + +namespace llvm { + +MCAsmParserExtension *createCOFFAsmParser() { + return new COFFAsmParser; +} + +} |