Index: llvm/include/llvm/CodeGen/AsmPrinter.h =================================================================== --- llvm/include/llvm/CodeGen/AsmPrinter.h +++ llvm/include/llvm/CodeGen/AsmPrinter.h @@ -841,11 +841,13 @@ virtual void emitFunctionHeaderComment(); /// Emit a blob of inline asm to the output streamer. + /// \p MI - the machine instruction of current inline asm. void emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, const MCTargetOptions &MCOptions, const MDNode *LocMDNode = nullptr, - InlineAsm::AsmDialect AsmDialect = InlineAsm::AD_ATT) const; + InlineAsm::AsmDialect AsmDialect = InlineAsm::AD_ATT, + const MachineInstr *MI = nullptr) const; /// This method formats and emits the specified machine instruction that is an /// inline asm. Index: llvm/include/llvm/MC/MCParser/MCAsmParser.h =================================================================== --- llvm/include/llvm/MC/MCParser/MCAsmParser.h +++ llvm/include/llvm/MC/MCParser/MCAsmParser.h @@ -16,6 +16,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmMacro.h" #include "llvm/Support/SMLoc.h" +#include "llvm/CodeGen/MachineInstr.h" #include #include #include @@ -177,7 +178,9 @@ void setShowParsedOperands(bool Value) { ShowParsedOperands = Value; } /// Run the parser on the input source buffer. - virtual bool Run(bool NoInitialTextSection, bool NoFinalize = false) = 0; + /// \p MI - the machine instruction of current inline asm. + virtual bool Run(bool NoInitialTextSection, bool NoFinalize = false, + const MachineInstr *MI = nullptr) = 0; virtual void setParsingMSInlineAsm(bool V) = 0; virtual bool isParsingMSInlineAsm() = 0; Index: llvm/include/llvm/MC/MCParser/MCParsedAsmOperand.h =================================================================== --- llvm/include/llvm/MC/MCParser/MCParsedAsmOperand.h +++ llvm/include/llvm/MC/MCParser/MCParsedAsmOperand.h @@ -91,6 +91,9 @@ /// dump - Print to the debug stream. virtual void dump() const; + + /// MIp - Pointer to the machine instruction of the current inlineAsm. + const MachineInstr *MIp; }; //===----------------------------------------------------------------------===// Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -71,7 +71,8 @@ void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, const MCTargetOptions &MCOptions, const MDNode *LocMDNode, - InlineAsm::AsmDialect Dialect) const { + InlineAsm::AsmDialect Dialect, + const MachineInstr *MI) const { assert(!Str.empty() && "Can't emit empty inline asm block"); // Remember if the buffer is nul terminated or not so we can avoid a copy. @@ -126,7 +127,8 @@ emitInlineAsmStart(); // Don't implicitly switch to the text section before the asm. (void)Parser->Run(/*NoInitialTextSection*/ true, - /*NoFinalize*/ true); + /*NoFinalize*/ true, + MI); emitInlineAsmEnd(STI, &TAP->getSTI()); } @@ -415,7 +417,7 @@ } emitInlineAsm(OS.str(), getSubtargetInfo(), TM.Options.MCOptions, LocMD, - MI->getInlineAsmDialect()); + MI->getInlineAsmDialect(), MI); // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't // enabled, so we use emitRawComment. Index: llvm/lib/MC/MCParser/AsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/AsmParser.cpp +++ llvm/lib/MC/MCParser/AsmParser.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/CodeGen/MachineInstr.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" @@ -184,15 +185,22 @@ bool AltMacroMode = false; protected: + /// \p MI - the machine instruction of current inline asm. + /// \p ErrorInfo - store the TSFlags of last machine instruction in the inline asm. virtual bool parseStatement(ParseStatementInfo &Info, - MCAsmParserSemaCallback *SI); + MCAsmParserSemaCallback *SI, + const MachineInstr *MI, + uint64_t &ErrorInfo); /// 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. + /// \p MI - the machine instruction of current inline asm. + /// \p ErrorInfo - store the TSFlags of last machine instruction in the inline asm. bool parseAndMatchAndEmitTargetInstruction(ParseStatementInfo &Info, StringRef IDVal, AsmToken ID, - SMLoc IDLoc); + SMLoc IDLoc, const MachineInstr *MI, + uint64_t &ErrorInfo); /// Should we emit DWARF describing this assembler source? (Returns false if /// the source has .file directives, which means we don't want to generate @@ -206,7 +214,9 @@ AsmParser &operator=(const AsmParser &) = delete; ~AsmParser() override; - bool Run(bool NoInitialTextSection, bool NoFinalize = false) override; + /// \p MI - the machine instruction of current inline asm. + bool Run(bool NoInitialTextSection, bool NoFinalize = false, + const MachineInstr *MI = nullptr) override; void addDirectiveHandler(StringRef Directive, ExtensionDirectiveHandler Handler) override { @@ -746,8 +756,12 @@ ~HLASMAsmParser() { Lexer.setSkipSpace(true); } + /// \p MI - the machine instruction of current inline asm. + /// \p ErrorInfo - store the TSFlags of last machine instruction in the inline asm. bool parseStatement(ParseStatementInfo &Info, - MCAsmParserSemaCallback *SI) override; + MCAsmParserSemaCallback *SI, + const MachineInstr *MI, + uint64_t &ErrorInfo) override; }; } // end anonymous namespace @@ -963,7 +977,7 @@ return true; } -bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { +bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize, const MachineInstr *MI) { LTODiscardSymbols.clear(); // Create the initial section, if requested. @@ -996,9 +1010,19 @@ getTargetParser().onBeginOfFile(); // While we have input, parse each statement. + // ErrorInfo - store the TSFlags of last machine instruction in the + // inline asm. Because target mips needs this TSFlags to check whether + // current instruction lie in forbidden slot. Reuse the parameter + // ErrorInfo of function MatchAndEmitInstruction. The parameter passed + // in represents the last instruction TSFlags, passed out represents + // the current instruction TSFlags. + uint64_t ErrorInfo = 0; while (Lexer.isNot(AsmToken::Eof)) { ParseStatementInfo Info(&AsmStrRewrites); - bool Parsed = parseStatement(Info, nullptr); + // MI - the machine instruction of current inline asm. Because target + // mips needs this pointer to get next machine instruction from current + // inlineAsm in MBB. + bool Parsed = parseStatement(Info, nullptr, MI, ErrorInfo); // If we have a Lexer Error we are on an Error Token. Load in Lexer Error // for printing ErrMsg via Lex() only if no (presumably better) parser error @@ -1780,7 +1804,9 @@ /// ::= Label* Directive ...Operands... EndOfStatement /// ::= Label* Identifier OperandList* EndOfStatement bool AsmParser::parseStatement(ParseStatementInfo &Info, - MCAsmParserSemaCallback *SI) { + MCAsmParserSemaCallback *SI, + const MachineInstr *MI, + uint64_t &ErrorInfo) { assert(!hasPendingError() && "parseStatement started with pending error"); // Eat initial spaces and comments while (Lexer.is(AsmToken::Space)) @@ -2306,20 +2332,22 @@ if (checkForValidSection()) return true; - return parseAndMatchAndEmitTargetInstruction(Info, IDVal, ID, IDLoc); + return parseAndMatchAndEmitTargetInstruction(Info, IDVal, ID, IDLoc, MI, ErrorInfo); } bool AsmParser::parseAndMatchAndEmitTargetInstruction(ParseStatementInfo &Info, StringRef IDVal, AsmToken ID, - SMLoc IDLoc) { + SMLoc IDLoc, + const MachineInstr *MI, + uint64_t &ErrorInfo) { // 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; - + Info.ParsedOperands[0]->MIp = MI; // Dump the parsed representation, if requested. if (getShowParsedOperands()) { SmallString<256> Str; @@ -2372,7 +2400,6 @@ // If parsing succeeded, match the instruction. if (!ParseHadError) { - uint64_t ErrorInfo; if (getTargetParser().MatchAndEmitInstruction( IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo, getTargetParser().isParsingMSInlineAsm())) @@ -5973,13 +6000,14 @@ // While we have input, parse each statement. unsigned InputIdx = 0; unsigned OutputIdx = 0; + uint64_t ErrorInfo = 0; while (getLexer().isNot(AsmToken::Eof)) { // Parse curly braces marking block start/end if (parseCurlyBlockScope(AsmStrRewrites)) continue; ParseStatementInfo Info(&AsmStrRewrites); - bool StatementErr = parseStatement(Info, &SI); + bool StatementErr = parseStatement(Info, &SI, nullptr, ErrorInfo); if (StatementErr || Info.ParseError) { // Emit pending errors if any exist. @@ -6282,12 +6310,15 @@ // any spaces to get to the OperandEntries. lexLeadingSpaces(); + uint64_t ErrorInfo = 0; return parseAndMatchAndEmitTargetInstruction( - Info, OperationEntryVal, OperationEntryTok, OperationEntryLoc); + Info, OperationEntryVal, OperationEntryTok, OperationEntryLoc, nullptr, ErrorInfo); } bool HLASMAsmParser::parseStatement(ParseStatementInfo &Info, - MCAsmParserSemaCallback *SI) { + MCAsmParserSemaCallback *SI, + const MachineInstr *MI, + uint64_t &ErrorInfo) { assert(!hasPendingError() && "parseStatement started with pending error"); // Should the first token be interpreted as a HLASM Label. Index: llvm/lib/MC/MCParser/MasmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/MasmParser.cpp +++ llvm/lib/MC/MCParser/MasmParser.cpp @@ -474,7 +474,9 @@ MasmParser &operator=(const MasmParser &) = delete; ~MasmParser() override; - bool Run(bool NoInitialTextSection, bool NoFinalize = false) override; + /// \p MI - the machine instruction of current inline asm. + bool Run(bool NoInitialTextSection, bool NoFinalize = false, + const MachineInstr *MI = nullptr) override; void addDirectiveHandler(StringRef Directive, ExtensionDirectiveHandler Handler) override { @@ -1335,7 +1337,7 @@ return true; } -bool MasmParser::Run(bool NoInitialTextSection, bool NoFinalize) { +bool MasmParser::Run(bool NoInitialTextSection, bool NoFinalize, const MachineInstr *MI) { // Create the initial section, if requested. if (!NoInitialTextSection) Out.initSections(false, getTargetParser().getSTI()); Index: llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" @@ -438,8 +439,11 @@ bool canUseATReg(); + // Get MI from Operands, the parameter ErrorInfo passed in represents the last + // instruction TSFlags, passed out represents the current instruction TSFlags. bool processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, - const MCSubtargetInfo *STI); + const MCSubtargetInfo *STI, OperandVector &Operands, + uint64_t &ErrorInfo); // Helper function that checks if the value of a vector index is within the // boundaries of accepted values for each RegisterKind @@ -1860,13 +1864,35 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, - const MCSubtargetInfo *STI) { + const MCSubtargetInfo *STI, + OperandVector &Operands, + uint64_t &RecvErrorInfo) { MipsTargetStreamer &TOut = getTargetStreamer(); const unsigned Opcode = Inst.getOpcode(); const MCInstrDesc &MCID = MII.get(Opcode); bool ExpandedJalSym = false; + // When the previous instruction has forbidden slot and the current + // instruction is CTI and .set reorder has been used, need insert nop. + bool needInsertNop = false; + // When the current instruction has forbidden slot and also is the last + // in current inline asm, need go to check next instruction by MI from + // the current inline asm in MBB, if it is CTI or inline asm, need insert + // nop. + bool gonext = false; + // Receive the TSFlags of last instruction. + uint64_t LastErrorInfo = RecvErrorInfo; + Inst.setLoc(IDLoc); + if ((LastErrorInfo & MipsII::HasForbiddenSlot) && + (MCID.TSFlags & MipsII::IsCTI)) { + needInsertNop = AssemblerOptions.back()->isReorder(); + if (needInsertNop) { + TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst), IDLoc, STI); + } + } + //Store the TSFlags of current instruction and passed out to the caller. + RecvErrorInfo = MCID.TSFlags; if (MCID.isBranch() || MCID.isCall()) { MCOperand Offset; @@ -2354,6 +2380,23 @@ Warning(IDLoc, "no .cprestore used in PIC mode"); } + if (MCID.TSFlags & MipsII::HasForbiddenSlot) { + AsmToken ID = getTok(); + getLexer().Lex(); + if(getLexer().is(AsmToken::Eof)) { + gonext = true; + } + getLexer().UnLex(ID); + if (true == gonext) { + const MachineInstr *MIp = Operands[0]->MIp; + if (MIp != NULL) { + auto I = std::next(MIp->getIterator()); + if (I->isInlineAsm() || (I->getDesc().TSFlags & MipsII::IsCTI)) + TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst), IDLoc, STI); + } + } + } + return false; } @@ -5918,13 +5961,18 @@ uint64_t &ErrorInfo, bool MatchingInlineAsm) { MCInst Inst; + uint64_t RecvErrorInfo = ErrorInfo; unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); switch (MatchResult) { case Match_Success: - if (processInstruction(Inst, IDLoc, Out, STI)) + if (processInstruction(Inst, IDLoc, Out, STI, Operands, RecvErrorInfo)) { + //Passed out TSFlags by ErrorInfo. + ErrorInfo = RecvErrorInfo; return true; + } + ErrorInfo = RecvErrorInfo; return false; case Match_MissingFeature: Error(IDLoc, "instruction requires a CPU feature not currently enabled"); Index: llvm/lib/Target/Mips/MipsInstrInfo.cpp =================================================================== --- llvm/lib/Target/Mips/MipsInstrInfo.cpp +++ llvm/lib/Target/Mips/MipsInstrInfo.cpp @@ -575,6 +575,7 @@ /// other instructions for handling forbidden slots. Consider inline assembly /// as unsafe as well. bool MipsInstrInfo::SafeInForbiddenSlot(const MachineInstr &MI) const { + //FIXME: Best to check whether the first instruction of inlineAsm is CTI if (MI.isInlineAsm()) return false; Index: llvm/test/CodeGen/Mips/llvm-ir/forbidden-slot-ir.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/Mips/llvm-ir/forbidden-slot-ir.ll @@ -0,0 +1,46 @@ +target triple = "mipsisa32r6el-unknown-linux-gnu" + +; RUN: llc -filetype=asm %s -o - | FileCheck %s --check-prefix=MIPSELR6 +; Function Attrs: noinline nounwind optnone uwtable +define i1 @foo0() nounwind { +; MIPSELR6: bnezc $1, $BB0_2 +; MIPSELR6-NEXT: nop +; MIPSELR6: jr $ra +entry: + %0 = icmp eq i32 0, 1 + br i1 %0, label %2, label %3 + ret i1 %0 +2: + ret i1 %0 +3: + ret i1 %0 +} + +define i32 @foo1() nounwind { +; MIPSELR6: beqzc $2, $tmp0 +; MIPSELR6-NEXT: nop +; MIPSELR6: jrc $ra +entry: + %0 = tail call i32 asm "1: addiu $0, $$0, 1; beqzc $0, 1b;", "=r"() nounwind + ret i32 %0 +} + +define i32 @foo2() nounwind { +; MIPSELR6: beqzc $9, End +; MIPSELR6-NEXT: nop +; MIPSELR6: addiu $9, $9, 1 +entry: + %0 = tail call i32 asm "beqzc $$t1, End;", "=r"() nounwind + %1 = tail call i32 asm "addiu $$t1, $$t1, 1;", "=r"() nounwind + %2 = add nsw i32 %1, %0 + ret i32 %2 +} + +define i32 @foo3() nounwind { +; MIPSELR6: beqzc $2, $tmp1 +; MIPSELR6-NEXT: nop +; MIPSELR6: j End +entry: + %0 = tail call i32 asm "1: addiu $0, $$0, 1; beqzc $0, 1b; j End;", "=r"() nounwind + ret i32 %0 +} Index: llvm/test/MC/Mips/forbidden-slot.s =================================================================== --- /dev/null +++ llvm/test/MC/Mips/forbidden-slot.s @@ -0,0 +1,16 @@ +# RUN: clang --target=mipsel-linux-gnu -march=mips32r6 -c %s -o tmp.o +# RUN: llvm-objdump -d tmp.o | FileCheck %s --check-prefix=MIPSELR6 + +# MIPSELR6: beqzc $9, 0x0 +# MIPSELR6-NEXT: b 0x0 +# MIPSELR6: beqzc $9, 0x8 +# MIPSELR6-NEXT: nop +# MIPSELR6: b 0x8 + .set noreorder +aaa: + beqzc $t1, aaa + b aaa + .set reorder +bbb: + beqzc $t1, bbb + b bbb