diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 6e5be8be72d4f..f37f0918b4b8c 100644 --- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -13,6 +13,7 @@ #include "MipsTargetStreamer.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" @@ -26,6 +27,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/TargetRegistry.h" +#include using namespace llvm; @@ -38,23 +40,35 @@ class MCInstrInfo; namespace { class MipsAssemblerOptions { public: - MipsAssemblerOptions() : ATReg(1), Reorder(true), Macro(true) {} + MipsAssemblerOptions(uint64_t Features_) : + ATReg(1), Reorder(true), Macro(true), Features(Features_) {} - unsigned getATRegNum() { return ATReg; } + MipsAssemblerOptions(const MipsAssemblerOptions *Opts) { + ATReg = Opts->getATRegNum(); + Reorder = Opts->isReorder(); + Macro = Opts->isMacro(); + Features = Opts->getFeatures(); + } + + unsigned getATRegNum() const { return ATReg; } bool setATReg(unsigned Reg); - bool isReorder() { return Reorder; } + bool isReorder() const { return Reorder; } void setReorder() { Reorder = true; } void setNoReorder() { Reorder = false; } - bool isMacro() { return Macro; } + bool isMacro() const { return Macro; } void setMacro() { Macro = true; } void setNoMacro() { Macro = false; } + uint64_t getFeatures() const { return Features; } + void setFeatures(uint64_t Features_) { Features = Features_; } + private: unsigned ATReg; bool Reorder; bool Macro; + uint64_t Features; }; } @@ -67,7 +81,7 @@ class MipsAsmParser : public MCTargetAsmParser { MCSubtargetInfo &STI; MCAsmParser &Parser; - MipsAssemblerOptions Options; + SmallVector, 2> AssemblerOptions; #define GET_ASSEMBLER_HEADER #include "MipsGenAsmMatcher.inc" @@ -157,6 +171,8 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseSetNoReorderDirective(); bool parseSetNoMips16Directive(); bool parseSetFpDirective(); + bool parseSetPopDirective(); + bool parseSetPushDirective(); bool parseSetAssignment(); @@ -205,6 +221,7 @@ class MipsAsmParser : public MCTargetAsmParser { setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); } + AssemblerOptions.back()->setFeatures(getAvailableFeatures()); } void clearFeatureBits(uint64_t Feature, StringRef FeatureString) { @@ -212,6 +229,7 @@ class MipsAsmParser : public MCTargetAsmParser { setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); } + AssemblerOptions.back()->setFeatures(getAvailableFeatures()); } public: @@ -228,6 +246,16 @@ class MipsAsmParser : public MCTargetAsmParser { : MCTargetAsmParser(), STI(sti), Parser(parser) { // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + + // Remember the initial assembler options. The user can not modify these. + MipsAssemblerOptions *TmpAOPtr = + new MipsAssemblerOptions(getAvailableFeatures()); + AssemblerOptions.push_back(std::unique_ptr(TmpAOPtr)); + + // Create an assembler options environment for the user to modify. + TmpAOPtr = new MipsAssemblerOptions(getAvailableFeatures()); + AssemblerOptions.push_back(std::unique_ptr(TmpAOPtr)); + TmpAOPtr = nullptr; getTargetStreamer().updateABIInfo(*this); @@ -961,7 +989,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, "nop instruction"); } - if (MCID.hasDelaySlot() && Options.isReorder()) { + if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) { // If this instruction has a delay slot and .set reorder is active, // emit a NOP after it. Instructions.push_back(Inst); @@ -1424,7 +1452,8 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, } void MipsAsmParser::WarnIfAssemblerTemporary(int RegIndex, SMLoc Loc) { - if ((RegIndex != 0) && ((int)Options.getATRegNum() == RegIndex)) { + if ((RegIndex != 0) && + ((int)AssemblerOptions.back()->getATRegNum() == RegIndex)) { if (RegIndex == 1) Warning(Loc, "Used $at without \".set noat\""); else @@ -1573,7 +1602,7 @@ bool MipsAssemblerOptions::setATReg(unsigned Reg) { } int MipsAsmParser::getATReg(SMLoc Loc) { - int AT = Options.getATRegNum(); + int AT = AssemblerOptions.back()->getATRegNum(); if (AT == 0) reportParseError(Loc, "Pseudo instruction requires $at, which is not available"); @@ -2328,7 +2357,7 @@ bool MipsAsmParser::reportParseError(SMLoc Loc, Twine ErrorMsg) { bool MipsAsmParser::parseSetNoAtDirective() { // Line should look like: ".set noat". // set at reg to 0. - Options.setATReg(0); + AssemblerOptions.back()->setATReg(0); // eat noat Parser.Lex(); // If this is not the end of the statement, report an error. @@ -2346,7 +2375,7 @@ bool MipsAsmParser::parseSetAtDirective() { int AtRegNo; getParser().Lex(); if (getLexer().is(AsmToken::EndOfStatement)) { - Options.setATReg(1); + AssemblerOptions.back()->setATReg(1); Parser.Lex(); // Consume the EndOfStatement. return false; } else if (getLexer().is(AsmToken::Equal)) { @@ -2371,7 +2400,7 @@ bool MipsAsmParser::parseSetAtDirective() { return false; } - if (!Options.setATReg(AtRegNo)) { + if (!AssemblerOptions.back()->setATReg(AtRegNo)) { reportParseError("unexpected token in statement"); return false; } @@ -2396,7 +2425,7 @@ bool MipsAsmParser::parseSetReorderDirective() { reportParseError("unexpected token in statement"); return false; } - Options.setReorder(); + AssemblerOptions.back()->setReorder(); getTargetStreamer().emitDirectiveSetReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; @@ -2409,7 +2438,7 @@ bool MipsAsmParser::parseSetNoReorderDirective() { reportParseError("unexpected token in statement"); return false; } - Options.setNoReorder(); + AssemblerOptions.back()->setNoReorder(); getTargetStreamer().emitDirectiveSetNoReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; @@ -2422,7 +2451,7 @@ bool MipsAsmParser::parseSetMacroDirective() { reportParseError("unexpected token in statement"); return false; } - Options.setMacro(); + AssemblerOptions.back()->setMacro(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2434,11 +2463,11 @@ bool MipsAsmParser::parseSetNoMacroDirective() { reportParseError("`noreorder' must be set before `nomacro'"); return false; } - if (Options.isReorder()) { + if (AssemblerOptions.back()->isReorder()) { reportParseError("`noreorder' must be set before `nomacro'"); return false; } - Options.setNoMacro(); + AssemblerOptions.back()->setNoMacro(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2481,6 +2510,39 @@ bool MipsAsmParser::parseSetFpDirective() { return false; } +bool MipsAsmParser::parseSetPopDirective() { + SMLoc Loc = getLexer().getLoc(); + + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + // Always keep an element on the options "stack" to prevent the user + // from changing the initial options. This is how we remember them. + if (AssemblerOptions.size() == 2) + return reportParseError(Loc, ".set pop with no .set push"); + + AssemblerOptions.pop_back(); + setAvailableFeatures(AssemblerOptions.back()->getFeatures()); + + getTargetStreamer().emitDirectiveSetPop(); + return false; +} + +bool MipsAsmParser::parseSetPushDirective() { + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token, expected end of statement"); + + // Create a copy of the current assembler options environment and push it. + MipsAssemblerOptions *TmpAOPtr = + new MipsAssemblerOptions(AssemblerOptions.back().get()); + AssemblerOptions.push_back(std::unique_ptr(TmpAOPtr)); + + getTargetStreamer().emitDirectiveSetPush(); + return false; +} + bool MipsAsmParser::parseSetAssignment() { StringRef Name; const MCExpr *Value; @@ -2551,7 +2613,7 @@ bool MipsAsmParser::eatComma(StringRef ErrorStr) { } bool MipsAsmParser::parseDirectiveCPLoad(SMLoc Loc) { - if (Options.isReorder()) + if (AssemblerOptions.back()->isReorder()) Warning(Loc, ".cpload in reorder section"); // FIXME: Warn if cpload is used in Mips16 mode. @@ -2664,6 +2726,10 @@ bool MipsAsmParser::parseDirectiveSet() { return parseSetAtDirective(); } else if (Tok.getString() == "fp") { return parseSetFpDirective(); + } else if (Tok.getString() == "pop") { + return parseSetPopDirective(); + } else if (Tok.getString() == "push") { + return parseSetPushDirective(); } else if (Tok.getString() == "reorder") { return parseSetReorderDirective(); } else if (Tok.getString() == "noreorder") { diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp index 4a178e2df7a97..fe0a2af278cd1 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -55,6 +55,8 @@ void MipsTargetStreamer::emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) { void MipsTargetStreamer::emitDirectiveSetMips32R2() {} void MipsTargetStreamer::emitDirectiveSetMips64() {} void MipsTargetStreamer::emitDirectiveSetMips64R2() {} +void MipsTargetStreamer::emitDirectiveSetPop() {} +void MipsTargetStreamer::emitDirectiveSetPush() {} void MipsTargetStreamer::emitDirectiveSetDsp() {} void MipsTargetStreamer::emitDirectiveCpload(unsigned RegNo) {} void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, @@ -171,6 +173,11 @@ void MipsTargetAsmStreamer::emitDirectiveSetDsp() { OS << "\t.set\tdsp\n"; setCanHaveModuleDir(false); } + +void MipsTargetAsmStreamer::emitDirectiveSetPop() { OS << "\t.set\tpop\n"; } + +void MipsTargetAsmStreamer::emitDirectiveSetPush() { OS << "\t.set\tpush\n"; } + // Print a 32 bit hex number with all numbers. static void printHex32(unsigned Value, raw_ostream &OS) { OS << "0x"; diff --git a/llvm/lib/Target/Mips/MipsTargetStreamer.h b/llvm/lib/Target/Mips/MipsTargetStreamer.h index 99f7d4c92cfba..bc7a72d254b1d 100644 --- a/llvm/lib/Target/Mips/MipsTargetStreamer.h +++ b/llvm/lib/Target/Mips/MipsTargetStreamer.h @@ -49,6 +49,8 @@ class MipsTargetStreamer : public MCTargetStreamer { virtual void emitDirectiveSetMips64(); virtual void emitDirectiveSetMips64R2(); virtual void emitDirectiveSetDsp(); + virtual void emitDirectiveSetPop(); + virtual void emitDirectiveSetPush(); // PIC support virtual void emitDirectiveCpload(unsigned RegNo); @@ -125,6 +127,8 @@ class MipsTargetAsmStreamer : public MipsTargetStreamer { void emitDirectiveSetMips64() override; void emitDirectiveSetMips64R2() override; void emitDirectiveSetDsp() override; + void emitDirectiveSetPop() override; + void emitDirectiveSetPush() override; // PIC support virtual void emitDirectiveCpload(unsigned RegNo); diff --git a/llvm/test/MC/Mips/set-push-pop-directives-bad.s b/llvm/test/MC/Mips/set-push-pop-directives-bad.s new file mode 100644 index 0000000000000..53d8b2308153f --- /dev/null +++ b/llvm/test/MC/Mips/set-push-pop-directives-bad.s @@ -0,0 +1,14 @@ +# RUN: not llvm-mc %s -triple=mipsel-unknown-linux -mcpu=mips32r2 2>%t1 +# RUN: FileCheck %s < %t1 + + .text + .set pop +# CHECK: :[[@LINE-1]]:14: error: .set pop with no .set push + .set push + .set pop + .set pop +# CHECK: :[[@LINE-1]]:14: error: .set pop with no .set push + .set push foo +# CHECK: :[[@LINE-1]]:19: error: unexpected token, expected end of statement + .set pop bar +# CHECK: :[[@LINE-1]]:18: error: unexpected token, expected end of statement diff --git a/llvm/test/MC/Mips/set-push-pop-directives.s b/llvm/test/MC/Mips/set-push-pop-directives.s new file mode 100644 index 0000000000000..0d6cd2d4dbe08 --- /dev/null +++ b/llvm/test/MC/Mips/set-push-pop-directives.s @@ -0,0 +1,47 @@ +# RUN: llvm-mc %s -triple=mipsel-unknown-linux -mcpu=mips32r2 -mattr=+msa | \ +# RUN: FileCheck %s +# .set push creates a copy of the current environment. +# .set pop restores the previous environment. +# FIXME: Also test resetting of .set macro/nomacro option. + + .text + # The first environment on the stack (with initial values). + lw $1, 65536($1) + b 1336 + addvi.b $w15, $w13, 18 + + # Create a new environment. + .set push + .set at=$ra # Test the ATReg option. + lw $1, 65536($1) + .set noreorder # Test the Reorder option. + b 1336 + + # Switch back to the first environment. + .set pop + lw $1, 65536($1) + b 1336 + addvi.b $w15, $w13, 18 + +# CHECK: lui $1, 1 +# CHECK: addu $1, $1, $1 +# CHECK: lw $1, 0($1) +# CHECK: b 1336 +# CHECK: nop +# CHECK: addvi.b $w15, $w13, 18 + +# CHECK: .set push +# CHECK: lui $ra, 1 +# CHECK: addu $ra, $ra, $1 +# CHECK: lw $1, 0($ra) +# CHECK: .set noreorder +# CHECK: b 1336 +# CHECK-NOT: nop + +# CHECK: .set pop +# CHECK: lui $1, 1 +# CHECK: addu $1, $1, $1 +# CHECK: lw $1, 0($1) +# CHECK: b 1336 +# CHECK: nop +# CHECK: addvi.b $w15, $w13, 18