Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -26,6 +26,8 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/TargetRegistry.h" +#include +#include using namespace llvm; @@ -38,7 +40,15 @@ namespace { class MipsAssemblerOptions { public: - MipsAssemblerOptions() : ATReg(1), Reorder(true), Macro(true) {} + MipsAssemblerOptions(uint64_t Features_) : + ATReg(1), Reorder(true), Macro(true), Features(Features_) {} + + MipsAssemblerOptions(MipsAssemblerOptions *Opts) { + ATReg = Opts->getATRegNum(); + Reorder = Opts->isReorder(); + Macro = Opts->isMacro(); + Features = Opts->getFeatures(); + } unsigned getATRegNum() { return ATReg; } bool setATReg(unsigned Reg); @@ -51,6 +61,9 @@ void setMacro() { Macro = true; } void setNomacro() { Macro = false; } + uint64_t getFeatures() { return Features; } + void setFeatures(uint64_t Features_) { Features = Features_; } + // Set of features that are either architecture features or referenced // by them (e.g.: FeatureNaN2008 implied by FeatureMips32r6). // The full table can be found in MipsGenSubtargetInfo.inc (MipsFeatureKV[]). @@ -69,6 +82,7 @@ unsigned ATReg; bool Reorder; bool Macro; + uint64_t Features; }; } @@ -81,7 +95,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' @@ -181,6 +195,8 @@ bool parseSetNoReorderDirective(); bool parseSetNoMips16Directive(); bool parseSetFpDirective(); + bool parseSetPopDirective(); + bool parseSetPushDirective(); bool parseSetAssignment(); @@ -252,6 +268,7 @@ STI.setFeatureBits(FeatureBits); setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(ArchFeature))); + AssemblerOptions.top()->setFeatures(getAvailableFeatures()); } void setFeatureBits(unsigned Feature, StringRef FeatureString) { @@ -259,6 +276,7 @@ setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); } + AssemblerOptions.top()->setFeatures(getAvailableFeatures()); } void clearFeatureBits(unsigned Feature, StringRef FeatureString) { @@ -266,6 +284,7 @@ setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); } + AssemblerOptions.top()->setFeatures(getAvailableFeatures()); } public: @@ -282,6 +301,16 @@ : MCTargetAsmParser(), STI(sti), Parser(parser) { // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + + // Cache the initial assembler options (for internal use only). + MipsAssemblerOptions *TmpAOPtr; + TmpAOPtr = new MipsAssemblerOptions(getAvailableFeatures()); + AssemblerOptions.push(std::unique_ptr(TmpAOPtr)); + + // Create an initial assembler options environment for the user. + TmpAOPtr = new MipsAssemblerOptions(getAvailableFeatures()); + AssemblerOptions.push(std::unique_ptr(TmpAOPtr)); + TmpAOPtr = nullptr; getTargetStreamer().updateABIInfo(*this); @@ -1017,7 +1046,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); @@ -1562,7 +1591,7 @@ } 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 @@ -1711,7 +1740,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"); @@ -2467,7 +2496,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. @@ -2485,7 +2514,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)) { @@ -2510,7 +2539,7 @@ return false; } - if (!Options.setATReg(AtRegNo)) { + if (!AssemblerOptions.top()->setATReg(AtRegNo)) { reportParseError("unexpected token in statement"); return false; } @@ -2535,7 +2564,7 @@ reportParseError("unexpected token in statement"); return false; } - Options.setReorder(); + AssemblerOptions.top()->setReorder(); getTargetStreamer().emitDirectiveSetReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; @@ -2548,7 +2577,7 @@ reportParseError("unexpected token in statement"); return false; } - Options.setNoreorder(); + AssemblerOptions.top()->setNoreorder(); getTargetStreamer().emitDirectiveSetNoReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; @@ -2561,7 +2590,7 @@ reportParseError("unexpected token in statement"); return false; } - Options.setMacro(); + AssemblerOptions.top()->setMacro(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2573,11 +2602,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; } @@ -2644,6 +2673,40 @@ 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 stack. + // This is how we cache the initial options. + if (AssemblerOptions.size() == 2) + return reportParseError(Loc, ".set pop with no .set push"); + + AssemblerOptions.pop(); + setAvailableFeatures(AssemblerOptions.top()->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; + TmpAOPtr = new MipsAssemblerOptions(AssemblerOptions.top().get()); + AssemblerOptions.push(std::unique_ptr(TmpAOPtr)); + TmpAOPtr = nullptr; + + getTargetStreamer().emitDirectiveSetPush(); + return false; +} + bool MipsAsmParser::parseSetAssignment() { StringRef Name; const MCExpr *Value; @@ -2781,7 +2844,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. @@ -2896,6 +2959,10 @@ return parseSetArchDirective(); } 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 @@ -70,6 +70,8 @@ void MipsTargetStreamer::emitDirectiveSetMips64() { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveSetMips64R2() { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveSetMips64R6() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetPop() {} +void MipsTargetStreamer::emitDirectiveSetPush() {} void MipsTargetStreamer::emitDirectiveSetDsp() { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveCpload(unsigned RegNo) {} void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, @@ -241,6 +243,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 @@ -61,6 +61,8 @@ virtual void emitDirectiveSetMips64R2(); virtual void emitDirectiveSetMips64R6(); virtual void emitDirectiveSetDsp(); + virtual void emitDirectiveSetPop(); + virtual void emitDirectiveSetPush(); // PIC support virtual void emitDirectiveCpload(unsigned RegNo); @@ -161,6 +163,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, expected end of statement + .set pop bar +# CHECK: :[[@LINE-1]]:18: error: unexpected token, expected end of statement Index: test/MC/Mips/set-push-pop-directives.s =================================================================== --- /dev/null +++ test/MC/Mips/set-push-pop-directives.s @@ -0,0 +1,53 @@ +# 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 + .set nomsa # Test the Features option (ASE). + .set mips32r6 # Test the Features option (ISA). + mod $2, $4, $6 + + # 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 nomsa +# CHECK: .set mips32r6 +# CHECK: mod $2, $4, $6 + +# 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