Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -41,6 +41,7 @@ class MachineConstantPoolValue; class MachineJumpTableInfo; class MachineModuleInfo; +class MCAsmContext; class MCAsmInfo; class MCCFIInstruction; class MCContext; @@ -78,6 +79,9 @@ /// generating (such as the current section etc). MCStreamer &OutStreamer; + /// Common context for inline assembly. + std::unique_ptr AsmContext; + /// The current machine function. const MachineFunction *MF; Index: include/llvm/MC/MCParser/MCAsmParser.h =================================================================== --- include/llvm/MC/MCParser/MCAsmParser.h +++ include/llvm/MC/MCParser/MCAsmParser.h @@ -197,8 +197,25 @@ virtual void checkForValidSection() = 0; }; +/// Auxiliary context interface to allow correct destruction. +class MCAsmContext { +protected: // Can only create subclasses. + MCAsmContext(); + +public: + virtual ~MCAsmContext(); +}; + +/// \brief Allocate an instance of assembly processing context. +MCAsmContext *createMCAsmContext(); + /// \brief Create an MCAsmParser instance. MCAsmParser *createMCAsmParser(SourceMgr &, MCContext &, + MCStreamer &, const MCAsmInfo &, + MCAsmContext &AC); + +/// \brief Create an MCAsmParser instance with internal MCAsmContext instance. +MCAsmParser *createMCAsmParser(SourceMgr &, MCContext &, MCStreamer &, const MCAsmInfo &); } // End llvm namespace Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -38,6 +38,7 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" @@ -169,6 +170,8 @@ MMI = getAnalysisIfAvailable(); MMI->AnalyzeModule(M); + AsmContext.reset(createMCAsmContext()); + // Initialize TargetLoweringObjectFile. const_cast(getObjFileLowering()) .Initialize(OutContext, TM); Index: lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -121,7 +121,7 @@ SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc()); std::unique_ptr Parser( - createMCAsmParser(SrcMgr, OutContext, OutStreamer, *MAI)); + createMCAsmParser(SrcMgr, OutContext, OutStreamer, *MAI, *AsmContext)); // Initialize the parser with a fresh subtarget info. It is better to use a // new STI here because the parser may modify it and we do not want those Index: lib/MC/MCParser/AsmParser.cpp =================================================================== --- lib/MC/MCParser/AsmParser.cpp +++ lib/MC/MCParser/AsmParser.cpp @@ -47,13 +47,37 @@ MCAsmParserSemaCallback::~MCAsmParserSemaCallback() {} +class MCAsmParserContext; + namespace { +/// \brief Helper wrapper around AsmToken to ensure that lifetime of the token +/// string is independent from its creator. +class MCAsmMacroArgToken { + /// Storage for token value. + std::string Value; + + /// Token kind. + AsmToken::TokenKind Kind; + + /// Wrapped token. + AsmToken Token; + +public: + MCAsmMacroArgToken(const AsmToken &_Token); + + AsmToken::TokenKind getKind() const { return Kind; } + + StringRef getStringContents() const { return Token.getStringContents(); } + + StringRef getString() const { return Token.getString(); } +}; + /// \brief Helper types for tracking macro definitions. -typedef std::vector MCAsmMacroArgument; +typedef std::vector MCAsmMacroArgument; typedef std::vector MCAsmMacroArguments; struct MCAsmMacroParameter { - StringRef Name; + std::string Name; MCAsmMacroArgument Value; bool Required; bool Vararg; @@ -64,8 +88,8 @@ typedef std::vector MCAsmMacroParameters; struct MCAsmMacro { - StringRef Name; - StringRef Body; + std::string Name; + std::string Body; MCAsmMacroParameters Parameters; public: @@ -106,7 +130,7 @@ ParseStatementInfo() : Opcode(~0U), ParseError(false), AsmRewrites(nullptr) {} ParseStatementInfo(SmallVectorImpl *rewrites) - : Opcode(~0), ParseError(false), AsmRewrites(rewrites) {} + : Opcode(~0), ParseError(false), AsmRewrites(rewrites) {} }; /// \brief The concrete assembly parser instance. @@ -118,6 +142,8 @@ MCContext &Ctx; MCStreamer &Out; const MCAsmInfo &MAI; + MCAsmParserContext *AC; + std::unique_ptr OwnedAC; SourceMgr &SrcMgr; SourceMgr::DiagHandlerTy SavedDiagHandler; void *SavedDiagContext; @@ -135,9 +161,6 @@ /// addDirectiveHandler. StringMap ExtensionDirectiveMap; - /// \brief Map of currently defined macros. - StringMap MacroMap; - /// \brief Stack of active macro instantiations. std::vector ActiveMacros; @@ -175,6 +198,8 @@ public: AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI); + AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, + const MCAsmInfo &MAI, MCAsmParserContext *AC); virtual ~AsmParser(); bool Run(bool NoInitialTextSection, bool NoFinalize = false) override; @@ -238,6 +263,8 @@ private: + void initialize(); + bool parseStatement(ParseStatementInfo &Info, MCAsmParserSemaCallback *SI); void eatToEndOfLine(); @@ -256,17 +283,6 @@ /// \brief Control a flag in the parser that enables or disables macros. void setMacrosEnabled(bool Flag) {MacrosEnabledFlag = Flag;} - /// \brief Lookup a previously defined macro. - /// \param Name Macro name. - /// \returns Pointer to macro. NULL if no such macro was defined. - const MCAsmMacro* lookupMacro(StringRef Name); - - /// \brief Define a new macro with the given name and information. - void defineMacro(StringRef Name, MCAsmMacro Macro); - - /// \brief Undefine a macro. If no such macro was defined, it's a no-op. - void undefineMacro(StringRef Name); - /// \brief Are we inside a macro instantiation? bool isInsideMacroInstantiation() {return !ActiveMacros.empty();} @@ -325,6 +341,10 @@ bool parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc); + /// \brief Wrapper for parseIdentifier to support argument of type + /// std::string. + bool parseIdentifier(std::string &Res); + // Generic (target and platform independent) directive parsing. enum DirectiveKind { DK_NO_DIRECTIVE, // Placeholder @@ -484,6 +504,24 @@ } +class MCAsmParserContext : public MCAsmContext { +private: + /// \brief Map of currently defined macros. + StringMap MacroMap; + +public: + /// \brief Lookup a previously defined macro. + /// \param Name Macro name. + /// \returns Pointer to macro. NULL if no such macro was defined. + const MCAsmMacro *lookupMacro(StringRef Name); + + /// \brief Define a new macro with the given name and information. + void defineMacro(StringRef Name, MCAsmMacro Macro); + + /// \brief Undefine a macro. If no such macro was defined, it's a no-op. + void undefineMacro(StringRef Name); +}; + enum { DEFAULT_ADDRSPACE = 0 }; AsmParser::AsmParser(SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out, @@ -492,6 +530,22 @@ PlatformParser(nullptr), CurBuffer(_SM.getMainFileID()), MacrosEnabledFlag(true), HadError(false), CppHashLineNumber(0), AssemblerDialect(~0U), IsDarwin(false), ParsingInlineAsm(false) { + OwnedAC.reset(new MCAsmParserContext()); + AC = OwnedAC.get(); + + initialize(); +} + +AsmParser::AsmParser(SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out, + const MCAsmInfo &_MAI, MCAsmParserContext *_AC) + : Lexer(_MAI), Ctx(_Ctx), Out(_Out), MAI(_MAI), AC(_AC), SrcMgr(_SM), + PlatformParser(nullptr), CurBuffer(_SM.getMainFileID()), + MacrosEnabledFlag(true), HadError(false), CppHashLineNumber(0), + AssemblerDialect(~0U), IsDarwin(false), ParsingInlineAsm(false) { + initialize(); +} + +void AsmParser::initialize() { // Save the old handler. SavedDiagHandler = SrcMgr.getDiagHandler(); SavedDiagContext = SrcMgr.getDiagContext(); @@ -500,7 +554,7 @@ Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer()); // Initialize the platform / file format parser. - switch (_Ctx.getObjectFileInfo()->getObjectFileType()) { + switch (Ctx.getObjectFileInfo()->getObjectFileType()) { case MCObjectFileInfo::IsCOFF: PlatformParser.reset(createCOFFAsmParser()); break; @@ -1336,7 +1390,7 @@ // If macros are enabled, check to see if this is a macro instantiation. if (areMacrosEnabled()) - if (const MCAsmMacro *M = lookupMacro(IDVal)) { + if (const MCAsmMacro *M = AC->lookupMacro(IDVal)) { return handleMacroEntry(M, IDLoc); } @@ -1856,6 +1910,23 @@ return false; } +MCAsmMacroArgToken::MCAsmMacroArgToken(const AsmToken &OriginalToken) { + Value = OriginalToken.getString(); + + Kind = OriginalToken.getKind(); + switch (Kind) { + default: + Token = AsmToken(Kind, Value); + break; + case AsmToken::BigNum: + Token = AsmToken(Kind, Value, OriginalToken.getAPIntVal()); + break; + case AsmToken::Integer: + Token = AsmToken(Kind, Value, OriginalToken.getIntVal()); + break; + } +} + MacroInstantiation::MacroInstantiation(SMLoc IL, int EB, SMLoc EL, size_t CondStackDepth) : InstantiationLoc(IL), ExitBuffer(EB), ExitLoc(EL), @@ -2077,17 +2148,6 @@ return TokError("too many positional arguments"); } -const MCAsmMacro *AsmParser::lookupMacro(StringRef Name) { - StringMap::iterator I = MacroMap.find(Name); - return (I == MacroMap.end()) ? nullptr : &I->getValue(); -} - -void AsmParser::defineMacro(StringRef Name, MCAsmMacro Macro) { - MacroMap.insert(std::make_pair(Name, std::move(Macro))); -} - -void AsmParser::undefineMacro(StringRef Name) { MacroMap.erase(Name); } - bool AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) { // Arbitrarily limit macro nesting depth, to match 'as'. We can eliminate // this, although we should protect against infinite loops. @@ -2259,6 +2319,14 @@ return false; } +bool AsmParser::parseIdentifier(std::string &Res) { + StringRef StringRefRes; + bool Result = parseIdentifier(StringRefRes); + Res = StringRefRes; + + return Result; +} + /// parseDirectiveSet: /// ::= .equ identifier ',' expression /// ::= .equiv identifier ',' expression @@ -3353,7 +3421,7 @@ eatToEndOfStatement(); } - if (lookupMacro(Name)) { + if (AC->lookupMacro(Name)) { return Error(DirectiveLoc, "macro '" + Name + "' is already defined"); } @@ -3361,7 +3429,7 @@ const char *BodyEnd = EndToken.getLoc().getPointer(); StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); checkForBadMacro(DirectiveLoc, Name, Body, Parameters); - defineMacro(Name, MCAsmMacro(Name, Body, std::move(Parameters))); + AC->defineMacro(Name, MCAsmMacro(Name, Body, std::move(Parameters))); return false; } @@ -3517,10 +3585,10 @@ if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.purgem' directive"); - if (!lookupMacro(Name)) + if (!AC->lookupMacro(Name)) return Error(DirectiveLoc, "macro '" + Name + "' is not defined"); - undefineMacro(Name); + AC->undefineMacro(Name); return false; } @@ -4715,8 +4783,32 @@ return false; } +const MCAsmMacro *MCAsmParserContext::lookupMacro(StringRef Name) { + StringMap::iterator I = MacroMap.find(Name); + return (I == MacroMap.end()) ? nullptr : &I->getValue(); +} + +void MCAsmParserContext::defineMacro(StringRef Name, MCAsmMacro Macro) { + MacroMap.insert(std::make_pair(Name, std::move(Macro))); +} + +void MCAsmParserContext::undefineMacro(StringRef Name) { MacroMap.erase(Name); } + +MCAsmContext::MCAsmContext() {} + +MCAsmContext::~MCAsmContext() {} + +MCAsmContext *llvm::createMCAsmContext() { return new MCAsmParserContext(); } + /// \brief Create an MCAsmParser instance. MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, + MCStreamer &Out, const MCAsmInfo &MAI, + MCAsmContext &AC) { + return new AsmParser(SM, C, Out, MAI, static_cast(&AC)); +} + +/// \brief Create an MCAsmParser instance with internal MCAsmContext instance. +MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, MCStreamer &Out, const MCAsmInfo &MAI) { return new AsmParser(SM, C, Out, MAI); } Index: test/CodeGen/Generic/inline-asm-macros-global-and-local.ll =================================================================== --- /dev/null +++ test/CodeGen/Generic/inline-asm-macros-global-and-local.ll @@ -0,0 +1,15 @@ +; RUN: not llc < %s 2>&1 > /dev/null | FileCheck %s + +; All macros defined in inline assembly should have module scope. + +; CHECK: error: macro 'MACRO' is already defined + +module asm ".macro MACRO" +module asm "\09.endm" + +define void @global_vs_local() { +entry: + call void asm sideeffect ".macro MACRO\0A\09.endm", ""() + call void asm sideeffect "MACRO", ""() + ret void +} Index: test/CodeGen/Generic/inline-asm-macros-local-and-local.ll =================================================================== --- /dev/null +++ test/CodeGen/Generic/inline-asm-macros-local-and-local.ll @@ -0,0 +1,12 @@ +; RUN: not llc < %s 2>&1 > /dev/null | FileCheck %s + +; All macros defined in inline assembly should have module scope. + +; CHECK: error: macro 'MACRO' is already defined + +define void @local_and_local() { +entry: + call void asm sideeffect ".macro MACRO\0A\09.endm", ""() + call void asm sideeffect ".macro MACRO\0A\09.endm", ""() + ret void +}