Index: llvm/include/llvm/MC/MCAsmInfo.h =================================================================== --- llvm/include/llvm/MC/MCAsmInfo.h +++ llvm/include/llvm/MC/MCAsmInfo.h @@ -130,6 +130,10 @@ /// at the beginning of statements. Defaults to false. bool RestrictCommentStringToStartOfStatement = false; + /// Should we emit the '\t' as the starting indentation marker for GNU inline + /// asm statements. Defaults to false. + bool EmitGNUAsmStartIndentationMarker = true; + /// This is appended to emitted labels. Defaults to ":" const char *LabelSuffix; @@ -566,6 +570,10 @@ } const char *getLabelSuffix() const { return LabelSuffix; } + bool getEmitGNUAsmStartIndentationMarker() const { + return EmitGNUAsmStartIndentationMarker; + } + bool useAssignmentForEHBegin() const { return UseAssignmentForEHBegin; } bool needsLocalForSize() const { return NeedsLocalForSize; } StringRef getPrivateGlobalPrefix() const { return PrivateGlobalPrefix; } Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -269,14 +269,18 @@ } 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(); + bool EmitGNUAsmStartIndentationMarker = + MAI->getEmitGNUAsmStartIndentationMarker(); + int AsmPrinterVariant = MAI->getAssemblerDialect(); - OS << '\t'; + if (EmitGNUAsmStartIndentationMarker) + OS << '\t'; while (*LastEmitted) { switch (*LastEmitted) { @@ -498,11 +502,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); Index: llvm/lib/MC/MCParser/AsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/AsmParser.cpp +++ llvm/lib/MC/MCParser/AsmParser.cpp @@ -183,6 +183,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); @@ -266,8 +278,6 @@ /// } private: - bool parseStatement(ParseStatementInfo &Info, - MCAsmParserSemaCallback *SI); bool parseCurlyBlockScope(SmallVectorImpl& AsmStrRewrites); bool parseCppHashLineFilenameComment(SMLoc L, bool SaveLocInfo = true); @@ -690,6 +700,33 @@ 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); + } + + ~HLASMAsmParser() { Lexer.setSkipSpace(true); } + + bool parseStatement(ParseStatementInfo &Info, + MCAsmParserSemaCallback *SI) override; +}; + } // end anonymous namespace namespace llvm { @@ -2230,69 +2267,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 @@ -6093,6 +6070,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 { @@ -6180,5 +6310,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); } Index: llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp =================================================================== --- llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -460,6 +460,12 @@ // A digit in HLASM is a number from 0 to 9. inline bool isHLASMAlnum(char C) { return isHLASMAlpha(C) || isDigit(C); } + // Are we parsing using the AD_HLASM dialect? + inline bool isParsingHLASM() { return getMAIAssemblerDialect() == AD_HLASM; } + + // Are we parsing using the AD_ATT dialect? + inline bool isParsingATT() { return getMAIAssemblerDialect() == AD_ATT; } + public: SystemZAsmParser(const MCSubtargetInfo &sti, MCAsmParser &parser, const MCInstrInfo &MII, @@ -1372,13 +1378,46 @@ // Read any subsequent operands. while (getLexer().is(AsmToken::Comma)) { Parser.Lex(); + + if (isParsingHLASM()) { + if (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"); } } @@ -1606,7 +1645,7 @@ } bool SystemZAsmParser::isLabel(AsmToken &Token) { - if (getMAIAssemblerDialect() == AD_ATT) + if (isParsingATT()) return true; // HLASM labels are ordinary symbols. Index: llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp =================================================================== --- llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp +++ llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp @@ -23,6 +23,7 @@ CommentString = AssemblerDialect == AD_HLASM ? "*" : "#"; RestrictCommentStringToStartOfStatement = (AssemblerDialect == AD_HLASM); + EmitGNUAsmStartIndentationMarker = (AssemblerDialect == AD_ATT); ZeroDirective = "\t.space\t"; Data64bitsDirective = "\t.quad\t"; UsesELFSectionDirectiveForBSS = true;