summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp101
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp7
-rw-r--r--llvm/lib/Target/Mips/MipsTargetStreamer.h4
-rw-r--r--llvm/test/MC/Mips/set-push-pop-directives-bad.s14
-rw-r--r--llvm/test/MC/Mips/set-push-pop-directives.s53
5 files changed, 162 insertions, 17 deletions
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index c00a2f8d361..0a9b36fba4a 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 <memory>
using namespace llvm;
@@ -38,19 +40,30 @@ 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_; }
+
// 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 @@ private:
unsigned ATReg;
bool Reorder;
bool Macro;
+ uint64_t Features;
};
}
@@ -81,7 +95,7 @@ class MipsAsmParser : public MCTargetAsmParser {
MCSubtargetInfo &STI;
MCAsmParser &Parser;
- MipsAssemblerOptions Options;
+ SmallVector<std::unique_ptr<MipsAssemblerOptions>, 2> 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 @@ class MipsAsmParser : public MCTargetAsmParser {
bool parseSetNoReorderDirective();
bool parseSetNoMips16Directive();
bool parseSetFpDirective();
+ bool parseSetPopDirective();
+ bool parseSetPushDirective();
bool parseSetAssignment();
@@ -252,6 +268,7 @@ class MipsAsmParser : public MCTargetAsmParser {
STI.setFeatureBits(FeatureBits);
setAvailableFeatures(
ComputeAvailableFeatures(STI.ToggleFeature(ArchFeature)));
+ AssemblerOptions.back()->setFeatures(getAvailableFeatures());
}
void setFeatureBits(uint64_t Feature, StringRef FeatureString) {
@@ -259,6 +276,7 @@ class MipsAsmParser : public MCTargetAsmParser {
setAvailableFeatures(
ComputeAvailableFeatures(STI.ToggleFeature(FeatureString)));
}
+ AssemblerOptions.back()->setFeatures(getAvailableFeatures());
}
void clearFeatureBits(uint64_t Feature, StringRef FeatureString) {
@@ -266,6 +284,7 @@ class MipsAsmParser : public MCTargetAsmParser {
setAvailableFeatures(
ComputeAvailableFeatures(STI.ToggleFeature(FeatureString)));
}
+ AssemblerOptions.back()->setFeatures(getAvailableFeatures());
}
public:
@@ -282,6 +301,16 @@ public:
: 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<MipsAssemblerOptions>(TmpAOPtr));
+
+ // Create an assembler options environment for the user to modify.
+ TmpAOPtr = new MipsAssemblerOptions(getAvailableFeatures());
+ AssemblerOptions.push_back(std::unique_ptr<MipsAssemblerOptions>(TmpAOPtr));
+ TmpAOPtr = nullptr;
getTargetStreamer().updateABIInfo(*this);
@@ -1017,7 +1046,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);
@@ -1562,7 +1591,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
@@ -1711,7 +1741,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");
@@ -2467,7 +2497,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.
@@ -2485,7 +2515,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)) {
@@ -2510,7 +2540,7 @@ bool MipsAsmParser::parseSetAtDirective() {
return false;
}
- if (!Options.setATReg(AtRegNo)) {
+ if (!AssemblerOptions.back()->setATReg(AtRegNo)) {
reportParseError("unexpected token in statement");
return false;
}
@@ -2535,7 +2565,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;
@@ -2548,7 +2578,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;
@@ -2561,7 +2591,7 @@ bool MipsAsmParser::parseSetMacroDirective() {
reportParseError("unexpected token in statement");
return false;
}
- Options.setMacro();
+ AssemblerOptions.back()->setMacro();
Parser.Lex(); // Consume the EndOfStatement.
return false;
}
@@ -2573,11 +2603,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;
}
@@ -2644,6 +2674,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<MipsAssemblerOptions>(TmpAOPtr));
+
+ getTargetStreamer().emitDirectiveSetPush();
+ return false;
+}
+
bool MipsAsmParser::parseSetAssignment() {
StringRef Name;
const MCExpr *Value;
@@ -2781,7 +2844,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.
@@ -2896,6 +2959,10 @@ bool MipsAsmParser::parseDirectiveSet() {
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") {
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
index d19307978d9..ddeef289fd5 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
@@ -70,6 +70,8 @@ void MipsTargetStreamer::emitDirectiveSetMips32R6() { forbidModuleDirective(); }
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 @@ void MipsTargetAsmStreamer::emitDirectiveSetDsp() {
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";
diff --git a/llvm/lib/Target/Mips/MipsTargetStreamer.h b/llvm/lib/Target/Mips/MipsTargetStreamer.h
index d689c343fad..5da21e65899 100644
--- a/llvm/lib/Target/Mips/MipsTargetStreamer.h
+++ b/llvm/lib/Target/Mips/MipsTargetStreamer.h
@@ -61,6 +61,8 @@ public:
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 @@ public:
void emitDirectiveSetMips64R2() override;
void emitDirectiveSetMips64R6() override;
void emitDirectiveSetDsp() override;
+ void emitDirectiveSetPop() override;
+ void emitDirectiveSetPush() override;
// PIC support
void emitDirectiveCpload(unsigned RegNo) override;
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 00000000000..53d8b230815
--- /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 00000000000..5f55b7c7e4d
--- /dev/null
+++ b/llvm/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
OpenPOWER on IntegriCloud