Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/TargetRegistry.h" +#include using namespace llvm; @@ -40,6 +41,13 @@ public: MipsAssemblerOptions() : aTReg(1), reorder(true), macro(true) {} + MipsAssemblerOptions(MipsAssemblerOptions *Opts) { + aTReg = Opts->getATRegNum(); + reorder = Opts->isReorder(); + macro = Opts->isMacro(); + CurrentFeatures = Opts->getCurrentFeatures(); + } + unsigned getATRegNum() { return aTReg; } bool setATReg(unsigned Reg); @@ -65,11 +73,25 @@ Mips::FeatureMips64r6 | Mips::FeatureCnMips | Mips::FeatureFP64Bit | Mips::FeatureGP64Bit | Mips::FeatureNaN2008; + unsigned getCurrentFeatures() { return CurrentFeatures; } + + void setCurrentFeatures(unsigned Features) { CurrentFeatures = Features; } + + static unsigned getInitialFeatures() { return InitialFeatures; } + + static void setInitialFeatures(unsigned Features) { + InitialFeatures = Features; + } + private: unsigned aTReg; bool reorder; bool macro; + unsigned CurrentFeatures; + static unsigned InitialFeatures; }; + +unsigned MipsAssemblerOptions::InitialFeatures; } namespace { @@ -81,7 +103,7 @@ MCSubtargetInfo &STI; MCAsmParser &Parser; - MipsAssemblerOptions Options; + std::stack AssemblerOptions; MCSymbol *CurrentFn; // Pointer to the function being parsed. It may be a // nullptr, which indicates that no function is currently // selected. This usually happens after an '.end func' @@ -180,6 +202,8 @@ bool parseSetNoReorderDirective(); bool parseSetNoMips16Directive(); bool parseSetFpDirective(); + bool parseSetPopDirective(); + bool parseSetPushDirective(); bool parseSetAssignment(); @@ -251,6 +275,8 @@ STI.setFeatureBits(FeatureBits); setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(ArchFeature))); + + AssemblerOptions.top()->setCurrentFeatures(getAvailableFeatures()); } void setFeatureBits(unsigned Feature, StringRef FeatureString) { @@ -258,6 +284,7 @@ setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); } + AssemblerOptions.top()->setCurrentFeatures(getAvailableFeatures()); } void clearFeatureBits(unsigned Feature, StringRef FeatureString) { @@ -265,6 +292,7 @@ setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); } + AssemblerOptions.top()->setCurrentFeatures(getAvailableFeatures()); } public: @@ -282,6 +310,15 @@ // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + AssemblerOptions.push(new MipsAssemblerOptions()); + + // Set the initial configuration given through the command-line or by using + // the default values. + AssemblerOptions.top()->setCurrentFeatures(getAvailableFeatures()); + + // We cache the initial configuration here so that it's always retrievable. + AssemblerOptions.top()->setInitialFeatures(getAvailableFeatures()); + getTargetStreamer().updateABIInfo(*this); // Assert exactly one ABI was chosen. @@ -1016,7 +1053,7 @@ "nop instruction"); } - if (MCID.hasDelaySlot() && Options.isReorder()) { + if (MCID.hasDelaySlot() && AssemblerOptions.top()->isReorder()) { // If this instruction has a delay slot and .set reorder is active, // emit a NOP after it. Instructions.push_back(Inst); @@ -1561,7 +1598,8 @@ } void MipsAsmParser::WarnIfAssemblerTemporary(int RegIndex, SMLoc Loc) { - if ((RegIndex != 0) && ((int)Options.getATRegNum() == RegIndex)) { + if ((RegIndex != 0) && + ((int)AssemblerOptions.top()->getATRegNum() == RegIndex)) { if (RegIndex == 1) Warning(Loc, "Used $at without \".set noat\""); else @@ -1710,7 +1748,7 @@ } int MipsAsmParser::getATReg(SMLoc Loc) { - int AT = Options.getATRegNum(); + int AT = AssemblerOptions.top()->getATRegNum(); if (AT == 0) reportParseError(Loc, "Pseudo instruction requires $at, which is not available"); @@ -2466,7 +2504,7 @@ bool MipsAsmParser::parseSetNoAtDirective() { // Line should look like: ".set noat". // set at reg to 0. - Options.setATReg(0); + AssemblerOptions.top()->setATReg(0); // eat noat Parser.Lex(); // If this is not the end of the statement, report an error. @@ -2484,7 +2522,7 @@ int AtRegNo; getParser().Lex(); if (getLexer().is(AsmToken::EndOfStatement)) { - Options.setATReg(1); + AssemblerOptions.top()->setATReg(1); Parser.Lex(); // Consume the EndOfStatement. return false; } else if (getLexer().is(AsmToken::Equal)) { @@ -2509,7 +2547,7 @@ return false; } - if (!Options.setATReg(AtRegNo)) { + if (!AssemblerOptions.top()->setATReg(AtRegNo)) { reportParseError("unexpected token in statement"); return false; } @@ -2534,7 +2572,7 @@ reportParseError("unexpected token in statement"); return false; } - Options.setReorder(); + AssemblerOptions.top()->setReorder(); getTargetStreamer().emitDirectiveSetReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; @@ -2547,7 +2585,7 @@ reportParseError("unexpected token in statement"); return false; } - Options.setNoreorder(); + AssemblerOptions.top()->setNoreorder(); getTargetStreamer().emitDirectiveSetNoReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; @@ -2560,7 +2598,7 @@ reportParseError("unexpected token in statement"); return false; } - Options.setMacro(); + AssemblerOptions.top()->setMacro(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2572,11 +2610,11 @@ reportParseError("`noreorder' must be set before `nomacro'"); return false; } - if (Options.isReorder()) { + if (AssemblerOptions.top()->isReorder()) { reportParseError("`noreorder' must be set before `nomacro'"); return false; } - Options.setNomacro(); + AssemblerOptions.top()->setNomacro(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2643,6 +2681,34 @@ return false; } +bool MipsAsmParser::parseSetPopDirective() { + SMLoc Loc = getLexer().getLoc(); + + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token in .set pop directive"); + + if (AssemblerOptions.size() == 1) + return reportParseError(Loc, ".set pop with no .set push"); + + AssemblerOptions.pop(); + setAvailableFeatures(AssemblerOptions.top()->getCurrentFeatures()); + + getTargetStreamer().emitDirectiveSetPop(); + return false; +} + +bool MipsAsmParser::parseSetPushDirective() { + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token in .set push directive"); + + AssemblerOptions.push(new MipsAssemblerOptions(AssemblerOptions.top())); + + getTargetStreamer().emitDirectiveSetPush(); + return false; +} + bool MipsAsmParser::parseSetAssignment() { StringRef Name; const MCExpr *Value; @@ -2745,7 +2811,7 @@ } bool MipsAsmParser::parseDirectiveCPLoad(SMLoc Loc) { - if (Options.isReorder()) + if (AssemblerOptions.top()->isReorder()) Warning(Loc, ".cpload in reorder section"); // FIXME: Warn if cpload is used in Mips16 mode. @@ -2858,6 +2924,10 @@ 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") { Index: lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -68,6 +68,8 @@ void MipsTargetStreamer::emitDirectiveSetMips64R2() { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveSetMips64R6() { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveSetDsp() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetPop() {} +void MipsTargetStreamer::emitDirectiveSetPush() {} void MipsTargetStreamer::emitDirectiveCpload(unsigned RegNo) {} void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, bool IsReg) { @@ -233,6 +235,11 @@ OS << "\t.set\tdsp\n"; MipsTargetStreamer::emitDirectiveSetDsp(); } + +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"; Index: lib/Target/Mips/MipsTargetStreamer.h =================================================================== --- lib/Target/Mips/MipsTargetStreamer.h +++ lib/Target/Mips/MipsTargetStreamer.h @@ -60,6 +60,8 @@ virtual void emitDirectiveSetMips64R2(); virtual void emitDirectiveSetMips64R6(); virtual void emitDirectiveSetDsp(); + virtual void emitDirectiveSetPop(); + virtual void emitDirectiveSetPush(); // PIC support virtual void emitDirectiveCpload(unsigned RegNo); @@ -159,6 +161,8 @@ void emitDirectiveSetMips64R2() override; void emitDirectiveSetMips64R6() override; void emitDirectiveSetDsp() override; + void emitDirectiveSetPop() override; + void emitDirectiveSetPush() override; // PIC support virtual void emitDirectiveCpload(unsigned RegNo); Index: test/MC/Mips/set-push-pop-directives-bad.s =================================================================== --- /dev/null +++ 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 in .set push directive + .set pop bar +# CHECK: :[[@LINE-1]]:18: error: unexpected token in .set pop directive Index: test/MC/Mips/set-push-pop-directives.s =================================================================== --- /dev/null +++ test/MC/Mips/set-push-pop-directives.s @@ -0,0 +1,50 @@ +## This test checks that .set push and .set pop work as they should i.e., +## '.set push' creates a new environment with the same properties of the +## old one and '.set pop' restores the old environment. +# RUN: llvm-mc %s -triple=mipsel-unknown-linux -show-encoding -mcpu=mips32 | \ +# RUN: FileCheck %s + + .text + .set noreorder + .set at=$ra + .set push + lw $1, 65536($1) + b 1336 + .set reorder + b 1336 + .set pop + b 1332 + +# Now let's check the .set mipsx directives... +# The -mcpu=mips32 option was specified on the command-line which means the current +# arch is mips32. + .set push + .set mips32r2 + .set push + .set mips32 + .set pop +# ARCH should be mips32r2 at this point. We must be able to assemble a mips32r2 instruction + ldxc1 $f0, $zero($5) + .set pop + +# CHECK: .text +# CHECK: .set noreorder +# CHECK: .set push +# CHECK: lui $ra, 1 +# CHECK: addu $ra, $ra, $1 +# CHECK: lw $1, 0($ra) +# CHECK: b 1336 +# CHECK-NOT: nop +# CHECK: .set reorder +# CHECK: b 1336 +# CHECK-NEXT: nop +# CHECK: .set pop +# CHECK: b 1332 +# CHECK-NOT: nop + +# CHECK: .set push +# CHECK: .set mips32r2 +# CHECK: .set push +# CHECK: .set mips32 +# CHECK: ldxc1 $f0, $zero($5) +# CHECK: .set pop