diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h --- a/llvm/include/llvm/MC/MCAsmInfo.h +++ b/llvm/include/llvm/MC/MCAsmInfo.h @@ -146,6 +146,10 @@ /// Default is true. bool AllowAdditionalComments = true; + /// Should we emit the '\t' as the starting indentation marker for GNU inline + /// asm statements. Defaults to true. + bool EmitGNUAsmStartIndentationMarker = true; + /// This is appended to emitted labels. Defaults to ":" const char *LabelSuffix; @@ -614,6 +618,9 @@ return RestrictCommentStringToStartOfStatement; } bool shouldAllowAdditionalComments() const { return AllowAdditionalComments; } + bool getEmitGNUAsmStartIndentationMarker() const { + return EmitGNUAsmStartIndentationMarker; + } const char *getLabelSuffix() const { return LabelSuffix; } bool useAssignmentForEHBegin() const { return UseAssignmentForEHBegin; } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -269,14 +269,16 @@ } static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, - MachineModuleInfo *MMI, int AsmPrinterVariant, + MachineModuleInfo *MMI, const MCAsmInfo *MAI, AsmPrinter *AP, unsigned LocCookie, raw_ostream &OS) { int CurVariant = -1; // The number of the {.|.|.} region we are in. const char *LastEmitted = AsmStr; // One past the last character emitted. unsigned NumOperands = MI->getNumOperands(); + int AsmPrinterVariant = MAI->getAssemblerDialect(); - OS << '\t'; + if (MAI->getEmitGNUAsmStartIndentationMarker()) + OS << '\t'; while (*LastEmitted) { switch (*LastEmitted) { @@ -498,11 +500,9 @@ SmallString<256> StringData; raw_svector_ostream OS(StringData); - // The variant of the current asmprinter. - int AsmPrinterVariant = MAI->getAssemblerDialect(); AsmPrinter *AP = const_cast(this); if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT) - EmitGCCInlineAsmStr(AsmStr, MI, MMI, AsmPrinterVariant, AP, LocCookie, OS); + EmitGCCInlineAsmStr(AsmStr, MI, MMI, MAI, AP, LocCookie, OS); else EmitMSInlineAsmStr(AsmStr, MI, MMI, AP, LocCookie, OS); diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -186,6 +186,18 @@ // Is alt macro mode enabled. bool AltMacroMode = false; +protected: + virtual bool parseStatement(ParseStatementInfo &Info, + MCAsmParserSemaCallback *SI); + + /// This routine uses the target specific ParseInstruction function to + /// parse an instruction into Operands, and then call the target specific + /// MatchAndEmit function to match and emit the instruction. + bool parseAndMatchAndEmitTargetInstruction(ParseInstructionInfo &IInfo, + ParseStatementInfo &Info, + StringRef Name, AsmToken Token, + SMLoc Loc); + public: AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB); @@ -273,8 +285,6 @@ /// } private: - bool parseStatement(ParseStatementInfo &Info, - MCAsmParserSemaCallback *SI); bool parseCurlyBlockScope(SmallVectorImpl& AsmStrRewrites); bool parseCppHashLineFilenameComment(SMLoc L, bool SaveLocInfo = true); @@ -701,6 +711,35 @@ void initializeCVDefRangeTypeMap(); }; +class HLASMAsmParser final : public AsmParser { +private: + MCAsmLexer &Lexer; + MCStreamer &Out; + + void lexLeadingSpaces() { + while (Lexer.is(AsmToken::Space)) + Lexer.Lex(); + } + + bool parseAsHLASMLabel(ParseStatementInfo &Info, MCAsmParserSemaCallback *SI); + bool parseAsMachineInstruction(ParseStatementInfo &Info, + MCAsmParserSemaCallback *SI); + +public: + HLASMAsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, + const MCAsmInfo &MAI, unsigned CB = 0) + : AsmParser(SM, Ctx, Out, MAI, CB), Lexer(getLexer()), Out(Out) { + Lexer.setSkipSpace(false); + Lexer.setAllowHashInIdentifier(true); + Lexer.setLexHLASMIntegers(true); + } + + ~HLASMAsmParser() { Lexer.setSkipSpace(true); } + + bool parseStatement(ParseStatementInfo &Info, + MCAsmParserSemaCallback *SI) override; +}; + } // end anonymous namespace namespace llvm { @@ -2260,69 +2299,9 @@ // Canonicalize the opcode to lower case. std::string OpcodeStr = IDVal.lower(); ParseInstructionInfo IInfo(Info.AsmRewrites); - bool ParseHadError = getTargetParser().ParseInstruction(IInfo, OpcodeStr, ID, - Info.ParsedOperands); - Info.ParseError = ParseHadError; - - // Dump the parsed representation, if requested. - if (getShowParsedOperands()) { - SmallString<256> Str; - raw_svector_ostream OS(Str); - OS << "parsed instruction: ["; - for (unsigned i = 0; i != Info.ParsedOperands.size(); ++i) { - if (i != 0) - OS << ", "; - Info.ParsedOperands[i]->print(OS); - } - OS << "]"; - - printMessage(IDLoc, SourceMgr::DK_Note, OS.str()); - } - - // Fail even if ParseInstruction erroneously returns false. - if (hasPendingError() || ParseHadError) - return true; - - // If we are generating dwarf for the current section then generate a .loc - // directive for the instruction. - if (!ParseHadError && enabledGenDwarfForAssembly() && - getContext().getGenDwarfSectionSyms().count( - getStreamer().getCurrentSectionOnly())) { - unsigned Line; - if (ActiveMacros.empty()) - Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer); - else - Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc, - ActiveMacros.front()->ExitBuffer); - // If we previously parsed a cpp hash file line comment then make sure the - // current Dwarf File is for the CppHashFilename if not then emit the - // Dwarf File table for it and adjust the line number for the .loc. - if (!CppHashInfo.Filename.empty()) { - unsigned FileNumber = getStreamer().emitDwarfFileDirective( - 0, StringRef(), CppHashInfo.Filename); - getContext().setGenDwarfFileNumber(FileNumber); - - unsigned CppHashLocLineNo = - SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf); - Line = CppHashInfo.LineNumber - 1 + (Line - CppHashLocLineNo); - } - - getStreamer().emitDwarfLocDirective( - getContext().getGenDwarfFileNumber(), Line, 0, - DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0, - StringRef()); - } - - // If parsing succeeded, match the instruction. - if (!ParseHadError) { - uint64_t ErrorInfo; - if (getTargetParser().MatchAndEmitInstruction( - IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo, - getTargetParser().isParsingMSInlineAsm())) - return true; - } - return false; + return parseAndMatchAndEmitTargetInstruction(IInfo, Info, OpcodeStr, ID, + IDLoc); } // Parse and erase curly braces marking block start/end @@ -6152,6 +6131,159 @@ return false; } +bool AsmParser::parseAndMatchAndEmitTargetInstruction( + ParseInstructionInfo &IInfo, ParseStatementInfo &Info, StringRef Name, + AsmToken Token, SMLoc Loc) { + + bool ParseHadError = getTargetParser().ParseInstruction(IInfo, Name, Token, + Info.ParsedOperands); + Info.ParseError = ParseHadError; + // Dump the parsed representation, if requested. + if (getShowParsedOperands()) { + SmallString<256> Str; + raw_svector_ostream OS(Str); + OS << "parsed instruction: ["; + for (unsigned I = 0; I != Info.ParsedOperands.size(); ++I) { + if (I != 0) + OS << ", "; + Info.ParsedOperands[I]->print(OS); + } + OS << "]"; + + printMessage(Loc, SourceMgr::DK_Note, OS.str()); + } + + // Fail even if ParseTargetInstruction erroneously returns false. + if (hasPendingError() || ParseHadError) + return true; + + // If we are generating dwarf for the current section then generate a .loc + // directive for the instruction. + if (!ParseHadError && enabledGenDwarfForAssembly() && + getContext().getGenDwarfSectionSyms().count( + getStreamer().getCurrentSectionOnly())) { + unsigned Line; + if (ActiveMacros.empty()) + Line = SrcMgr.FindLineNumber(Loc, CurBuffer); + else + Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc, + ActiveMacros.front()->ExitBuffer); + + // If we previously parsed a cpp hash file line comment then make sure the + // current Dwarf File is for the CppHashFilename if not then emit the + // Dwarf File table for it and adjust the line number for the .loc. + if (!CppHashInfo.Filename.empty()) { + unsigned FileNumber = getStreamer().emitDwarfFileDirective( + 0, StringRef(), CppHashInfo.Filename); + getContext().setGenDwarfFileNumber(FileNumber); + + unsigned CppHashLocLineNo = + SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf); + Line = CppHashInfo.LineNumber - 1 + (Line - CppHashLocLineNo); + } + + getStreamer().emitDwarfLocDirective( + getContext().getGenDwarfFileNumber(), Line, 0, + DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0, + StringRef()); + } + + // If parsing succeeded, match the instruction. + if (!ParseHadError) { + uint64_t ErrorInfo; + if (getTargetParser().MatchAndEmitInstruction( + Loc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo, + getTargetParser().isParsingMSInlineAsm())) + return true; + } + + return false; +} + +bool HLASMAsmParser::parseAsMachineInstruction(ParseStatementInfo &Info, + MCAsmParserSemaCallback *SI) { + AsmToken OperationEntryTok = Lexer.getTok(); + SMLoc OperationEntryLoc = OperationEntryTok.getLoc(); + StringRef OperationEntryVal; + + // If we see a new line or carriage return, emit the new line + // and lex it. + if (OperationEntryTok.is(AsmToken::EndOfStatement)) { + if (getTok().getString().front() == '\n' || + getTok().getString().front() == '\r') { + Out.AddBlankLine(); + Lex(); + return false; + } + } + + // Attempt to parse the first token as an Identifier + if (parseIdentifier(OperationEntryVal)) + return Error(OperationEntryLoc, "unexpected token at start of statement"); + + // Once we've parsed the operation entry successfully, lex + // any spaces to get to the OperandEntries. + lexLeadingSpaces(); + + // Canonicalize the opcode to lower case. + std::string OpcodeStr = OperationEntryVal.lower(); + ParseInstructionInfo IInfo(Info.AsmRewrites); + + return parseAndMatchAndEmitTargetInstruction( + IInfo, Info, OpcodeStr, OperationEntryTok, OperationEntryLoc); +} + +bool HLASMAsmParser::parseStatement(ParseStatementInfo &Info, + MCAsmParserSemaCallback *SI) { + assert(!hasPendingError() && "parseStatement started with pending error"); + + // Should the first token be interpreted as a machine instruction. + bool ShouldParseAsMachineInstruction = false; + // Should the first token be interpreted as a label (ordinary symbol). + bool ShouldParseAsLabel = false; + + // If a Name Entry exists, it should occur at the very + // start of the string. In this case, we should parse the + // first non-space token as a Label. + // If the Name entry is missing (i.e. there's some other + // token), then we attempt to parse the first non-space + // token as a Machine Instruction. + if (getTok().is(AsmToken::Space)) + ShouldParseAsMachineInstruction = true; + else + ShouldParseAsLabel = true; + + assert(!(ShouldParseAsMachineInstruction && ShouldParseAsLabel) && + "Cannot parse first token as both a label and an instruction"); + + // If we have an EndOfStatement (which includes the target's comment + // string) we can appropriately lex it early on) + if (Lexer.is(AsmToken::EndOfStatement)) { + // if this is a line comment we can drop it safely + if (getTok().getString().empty() || getTok().getString().front() == '\r' || + getTok().getString().front() == '\n') + Out.AddBlankLine(); + Lex(); + return false; + } + + // We have established how to parse the inline asm statement. + // Now we can safely lex any spaces to get to the + // first token. + lexLeadingSpaces(); + + if (ShouldParseAsMachineInstruction) { + if (parseAsMachineInstruction(Info, SI)) + return true; + return false; + } + + // Label parsing support isn't implemented completely (yet). + SMLoc Loc = getTok().getLoc(); + eatToEndOfStatement(); + return Error(Loc, "HLASM Label parsing support not yet implemented"); +} + namespace llvm { namespace MCParserUtils { @@ -6239,5 +6371,8 @@ MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB) { + if (C.getObjectFileInfo()->getTargetTriple().isOSzOS()) + return new HLASMAsmParser(SM, C, Out, MAI, CB); + return new AsmParser(SM, C, Out, MAI, CB); } diff --git a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp --- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -1381,13 +1381,44 @@ // Read any subsequent operands. while (getLexer().is(AsmToken::Comma)) { Parser.Lex(); + + if (isParsingHLASM() && getLexer().is(AsmToken::Space)) + return Error( + Parser.getTok().getLoc(), + "No space allowed between comma that separates operand entries"); + if (parseOperand(Operands, Name)) { return true; } } if (getLexer().isNot(AsmToken::EndOfStatement)) { SMLoc Loc = getLexer().getLoc(); - return Error(Loc, "unexpected token in argument list"); + if (isParsingHLASM()) { + // Under the HLASM variant, we could have the remark field + // The remark field occurs after the operation entries + // There is a space that separates the operation entries and the + // remark field. + + // We don't have a space, we immediately error out. + if (getTok().isNot(AsmToken::Space)) + return Error(Loc, "unexpected token in argument list"); + + // We've confirmed that there is a Remark field. + StringRef Remark(getLexer().LexUntilEndOfStatement()); + Parser.Lex(); + + // If there is nothing after the space, then there is nothing to emit + // We could have a situation as this: + // " \n" + // After lexing, we will have + // "\n" + // This isn't an explicit remark field, so we don't have to output + // this as a comment. + if (Remark.size()) + // Output the entire Remarks Field as a comment + getStreamer().AddComment(Remark); + } else + return Error(Loc, "unexpected token in argument list"); } } diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp @@ -29,6 +29,7 @@ AllowHashAtStartOfIdentifier = (AssemblerDialect == AD_HLASM); DotIsPC = (AssemblerDialect == AD_ATT); StarIsPC = (AssemblerDialect == AD_HLASM); + EmitGNUAsmStartIndentationMarker = (AssemblerDialect == AD_ATT); ZeroDirective = "\t.space\t"; Data64bitsDirective = "\t.quad\t";