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; @@ -618,6 +622,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,36 @@ 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); + Lexer.setLexHLASMStrings(true); + } + + ~HLASMAsmParser() { Lexer.setSkipSpace(true); } + + bool parseStatement(ParseStatementInfo &Info, + MCAsmParserSemaCallback *SI) override; +}; + } // end anonymous namespace namespace llvm { @@ -2260,7 +2300,16 @@ // Canonicalize the opcode to lower case. std::string OpcodeStr = IDVal.lower(); ParseInstructionInfo IInfo(Info.AsmRewrites); - bool ParseHadError = getTargetParser().ParseInstruction(IInfo, OpcodeStr, ID, + + return parseAndMatchAndEmitTargetInstruction(IInfo, Info, OpcodeStr, ID, + IDLoc); +} + +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; @@ -2269,14 +2318,14 @@ SmallString<256> Str; raw_svector_ostream OS(Str); OS << "parsed instruction: ["; - for (unsigned i = 0; i != Info.ParsedOperands.size(); ++i) { - if (i != 0) + for (unsigned I = 0; I != Info.ParsedOperands.size(); ++I) { + if (I != 0) OS << ", "; - Info.ParsedOperands[i]->print(OS); + Info.ParsedOperands[I]->print(OS); } OS << "]"; - printMessage(IDLoc, SourceMgr::DK_Note, OS.str()); + printMessage(Loc, SourceMgr::DK_Note, OS.str()); } // Fail even if ParseInstruction erroneously returns false. @@ -2290,7 +2339,7 @@ getStreamer().getCurrentSectionOnly())) { unsigned Line; if (ActiveMacros.empty()) - Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer); + Line = SrcMgr.FindLineNumber(Loc, CurBuffer); else Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc, ActiveMacros.front()->ExitBuffer); @@ -2304,7 +2353,7 @@ getContext().setGenDwarfFileNumber(FileNumber); unsigned CppHashLocLineNo = - SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf); + SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf); Line = CppHashInfo.LineNumber - 1 + (Line - CppHashLocLineNo); } @@ -2318,7 +2367,7 @@ if (!ParseHadError) { uint64_t ErrorInfo; if (getTargetParser().MatchAndEmitInstruction( - IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo, + Loc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo, getTargetParser().isParsingMSInlineAsm())) return true; } @@ -6124,6 +6173,90 @@ 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 { @@ -6211,5 +6344,8 @@ MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB) { + if (C.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,40 @@ // 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() && getTok().is(AsmToken::Space)) { + // 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'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 above, 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";