Index: llvm/include/llvm/MC/MCAsmInfo.h =================================================================== --- llvm/include/llvm/MC/MCAsmInfo.h +++ llvm/include/llvm/MC/MCAsmInfo.h @@ -126,6 +126,10 @@ /// "#" StringRef CommentString; + /// 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; @@ -559,6 +563,10 @@ StringRef getCommentString() const { return CommentString; } 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 @@ -270,13 +270,15 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, MachineModuleInfo *MMI, int AsmPrinterVariant, + bool EmitGNUAsmStartIndentationMarker, 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(); - OS << '\t'; + if (EmitGNUAsmStartIndentationMarker) + OS << '\t'; while (*LastEmitted) { switch (*LastEmitted) { @@ -498,12 +500,16 @@ 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); - else + if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT) { + // The variant of the current asmprinter. + int AsmPrinterVariant = MAI->getAssemblerDialect(); + // Whether to emit the Start Indentation marker. + bool EmitGNUAsmStartIndentationMarker = + MAI->getEmitGNUAsmStartIndentationMarker(); + EmitGCCInlineAsmStr(AsmStr, MI, MMI, AsmPrinterVariant, + EmitGNUAsmStartIndentationMarker, AP, LocCookie, OS); + } else EmitMSInlineAsmStr(AsmStr, MI, MMI, AP, LocCookie, OS); // Emit warnings if we use reserved registers on the clobber list, as Index: llvm/lib/MC/MCParser/AsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/AsmParser.cpp +++ llvm/lib/MC/MCParser/AsmParser.cpp @@ -132,9 +132,6 @@ /// SourceMgr object. unsigned CurBuffer; - AsmCond TheCondState; - std::vector TheCondStack; - /// maps directive names to handler methods in parser /// extensions. Extensions register themselves in this map by calling /// addDirectiveHandler. @@ -183,6 +180,28 @@ // Is alt macro mode enabled. bool AltMacroMode = false; +protected: + virtual bool parseStatement(ParseStatementInfo &Info, + MCAsmParserSemaCallback *SI); + + void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg, + SMRange Range = None) const { + ArrayRef Ranges(Range); + SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges); + } + + /// Should we emit DWARF describing this assembler source? (Returns false if + /// the source has .file directives, which means we don't want to generate + /// info describing the assembler source itself.) + bool enabledGenDwarfForAssembly(); + + /// Emit a .loc directive for the instruction (used when we are generating + /// dwarf for the current section). + void generateLOCDirectiveForInstruction(SMLoc Loc); + + AsmCond TheCondState; + std::vector TheCondStack; + public: AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB); @@ -266,8 +285,6 @@ /// } private: - bool parseStatement(ParseStatementInfo &Info, - MCAsmParserSemaCallback *SI); bool parseCurlyBlockScope(SmallVectorImpl& AsmStrRewrites); bool parseCppHashLineFilenameComment(SMLoc L, bool SaveLocInfo = true); @@ -301,20 +318,9 @@ /// Parse all macro arguments for a given macro. bool parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A); - void printMacroInstantiations(); - void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg, - SMRange Range = None) const { - ArrayRef Ranges(Range); - SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges); - } static void DiagHandler(const SMDiagnostic &Diag, void *Context); - /// Should we emit DWARF describing this assembler source? (Returns false if - /// the source has .file directives, which means we don't want to generate - /// info describing the assembler source itself.) - bool enabledGenDwarfForAssembly(); - /// Enter the specified file. This returns true on failure. bool enterIncludeFile(const std::string &Filename); @@ -690,6 +696,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 { @@ -867,6 +900,32 @@ return *tok; } +void AsmParser::generateLOCDirectiveForInstruction(SMLoc Loc) { + 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()); +} + bool AsmParser::enabledGenDwarfForAssembly() { // Check whether the user specified -g. if (!getContext().getGenDwarfForAssembly()) @@ -2258,30 +2317,7 @@ 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()); + generateLOCDirectiveForInstruction(IDLoc); } // If parsing succeeded, match the instruction. @@ -6093,6 +6129,133 @@ 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)) { + if (!TheCondState.Ignore) { + Lex(); // always eat a token + return Error(OperationEntryLoc, "unexpected token at start of statement"); + } + OperationEntryVal = ""; + } + + // 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); + bool ParseHadError = getTargetParser().ParseInstruction( + IInfo, OpcodeStr, OperationEntryTok, 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(OperationEntryLoc, 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())) { + generateLOCDirectiveForInstruction(OperationEntryLoc); + } + + // If parsing succeeded, match the instruction. + if (!ParseHadError) { + uint64_t ErrorInfo; + if (getTargetParser().MatchAndEmitInstruction( + OperationEntryLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo, + getTargetParser().isParsingMSInlineAsm())) + return true; + } + + return false; +} + +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 +6343,9 @@ MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB) { + if (C.getObjectFileInfo()->getTargetTriple().isOSzOS() && + MAI.getAssemblerDialect()) + 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 @@ -1372,13 +1372,47 @@ // Read any subsequent operands. while (getLexer().is(AsmToken::Comma)) { Parser.Lex(); + + if (getMAIAssemblerDialect()) { + 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 (getMAIAssemblerDialect()) { + // 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"); } } Index: llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp =================================================================== --- llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp +++ llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp @@ -21,6 +21,8 @@ MaxInstLength = 6; + EmitGNUAsmStartIndentationMarker = + (AssemblerDialect == AD_HLASM) ? false : true; CommentString = "#"; ZeroDirective = "\t.space\t"; Data64bitsDirective = "\t.quad\t";