summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
authorAlex Bradbury <asb@lowrisc.org>2018-11-28 16:39:14 +0000
committerAlex Bradbury <asb@lowrisc.org>2018-11-28 16:39:14 +0000
commit893e5bc77484e93d7219eb5aef3534cbe6a14bb5 (patch)
treef03fee86fe12d19d6e87f481c6fe03842585d687 /llvm
parent8d63aed45941eb40ee30cf80584d6fd024d56b53 (diff)
downloadbcm5719-llvm-893e5bc77484e93d7219eb5aef3534cbe6a14bb5.tar.gz
bcm5719-llvm-893e5bc77484e93d7219eb5aef3534cbe6a14bb5.zip
[RISCV] Support .option push and .option pop
This adds support in the RISCVAsmParser the storing of Subtarget feature bits to a stack so that they can be pushed/popped to enable/disable multiple features at once. Differential Revision: https://reviews.llvm.org/D46424 Patch by Lewis Revill. llvm-svn: 347774
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp47
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp2
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h2
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp8
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h4
-rw-r--r--llvm/test/MC/RISCV/option-invalid.s11
-rw-r--r--llvm/test/MC/RISCV/option-pushpop.s74
7 files changed, 146 insertions, 2 deletions
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 331eb2b361c..4e70ea402d8 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -14,6 +14,7 @@
#include "Utils/RISCVBaseInfo.h"
#include "Utils/RISCVMatInt.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
@@ -42,6 +43,8 @@ namespace {
struct RISCVOperand;
class RISCVAsmParser : public MCTargetAsmParser {
+ SmallVector<FeatureBitset, 4> FeatureBitStack;
+
SMLoc getLoc() const { return getParser().getTok().getLoc(); }
bool isRV64() const { return getSTI().hasFeature(RISCV::Feature64Bit); }
@@ -118,6 +121,20 @@ class RISCVAsmParser : public MCTargetAsmParser {
}
}
+ void pushFeatureBits() {
+ FeatureBitStack.push_back(getSTI().getFeatureBits());
+ }
+
+ bool popFeatureBits() {
+ if (FeatureBitStack.empty())
+ return true;
+
+ FeatureBitset FeatureBits = FeatureBitStack.pop_back_val();
+ copySTI().setFeatureBits(FeatureBits);
+ setAvailableFeatures(ComputeAvailableFeatures(FeatureBits));
+
+ return false;
+ }
public:
enum RISCVMatchResultTy {
Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
@@ -1285,6 +1302,33 @@ bool RISCVAsmParser::parseDirectiveOption() {
StringRef Option = Tok.getIdentifier();
+ if (Option == "push") {
+ getTargetStreamer().emitDirectiveOptionPush();
+
+ Parser.Lex();
+ if (Parser.getTok().isNot(AsmToken::EndOfStatement))
+ return Error(Parser.getTok().getLoc(),
+ "unexpected token, expected end of statement");
+
+ pushFeatureBits();
+ return false;
+ }
+
+ if (Option == "pop") {
+ SMLoc StartLoc = Parser.getTok().getLoc();
+ getTargetStreamer().emitDirectiveOptionPop();
+
+ Parser.Lex();
+ if (Parser.getTok().isNot(AsmToken::EndOfStatement))
+ return Error(Parser.getTok().getLoc(),
+ "unexpected token, expected end of statement");
+
+ if (popFeatureBits())
+ return Error(StartLoc, ".option pop with no .option push");
+
+ return false;
+ }
+
if (Option == "rvc") {
getTargetStreamer().emitDirectiveOptionRVC();
@@ -1335,7 +1379,8 @@ bool RISCVAsmParser::parseDirectiveOption() {
// Unknown option.
Warning(Parser.getTok().getLoc(),
- "unknown option, expected 'rvc', 'norvc', 'relax' or 'norelax'");
+ "unknown option, expected 'push', 'pop', 'rvc', 'norvc', 'relax' or "
+ "'norelax'");
Parser.eatToEndOfStatement();
return false;
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
index 62a087fb2e7..a6ba1e41e96 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
@@ -38,6 +38,8 @@ MCELFStreamer &RISCVTargetELFStreamer::getStreamer() {
return static_cast<MCELFStreamer &>(Streamer);
}
+void RISCVTargetELFStreamer::emitDirectiveOptionPush() {}
+void RISCVTargetELFStreamer::emitDirectiveOptionPop() {}
void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {}
void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {}
void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
index 3e050c8b530..1f36bbc4388 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
@@ -20,6 +20,8 @@ public:
MCELFStreamer &getStreamer();
RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
+ virtual void emitDirectiveOptionPush();
+ virtual void emitDirectiveOptionPop();
virtual void emitDirectiveOptionRVC();
virtual void emitDirectiveOptionNoRVC();
virtual void emitDirectiveOptionRelax();
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
index 33c59f839ef..8d5ef3dbd17 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
@@ -23,6 +23,14 @@ RISCVTargetAsmStreamer::RISCVTargetAsmStreamer(MCStreamer &S,
formatted_raw_ostream &OS)
: RISCVTargetStreamer(S), OS(OS) {}
+void RISCVTargetAsmStreamer::emitDirectiveOptionPush() {
+ OS << "\t.option\tpush\n";
+}
+
+void RISCVTargetAsmStreamer::emitDirectiveOptionPop() {
+ OS << "\t.option\tpop\n";
+}
+
void RISCVTargetAsmStreamer::emitDirectiveOptionRVC() {
OS << "\t.option\trvc\n";
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
index 365388ef85f..74ec9e30393 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
@@ -18,6 +18,8 @@ class RISCVTargetStreamer : public MCTargetStreamer {
public:
RISCVTargetStreamer(MCStreamer &S);
+ virtual void emitDirectiveOptionPush() = 0;
+ virtual void emitDirectiveOptionPop() = 0;
virtual void emitDirectiveOptionRVC() = 0;
virtual void emitDirectiveOptionNoRVC() = 0;
virtual void emitDirectiveOptionRelax() = 0;
@@ -31,6 +33,8 @@ class RISCVTargetAsmStreamer : public RISCVTargetStreamer {
public:
RISCVTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
+ void emitDirectiveOptionPush() override;
+ void emitDirectiveOptionPop() override;
void emitDirectiveOptionRVC() override;
void emitDirectiveOptionNoRVC() override;
void emitDirectiveOptionRelax() override;
diff --git a/llvm/test/MC/RISCV/option-invalid.s b/llvm/test/MC/RISCV/option-invalid.s
index 904a50cdaed..8333f1c1997 100644
--- a/llvm/test/MC/RISCV/option-invalid.s
+++ b/llvm/test/MC/RISCV/option-invalid.s
@@ -13,5 +13,14 @@
# CHECK: error: unexpected token, expected end of statement
.option rvc foo
-# CHECK: warning: unknown option, expected 'rvc', 'norvc', 'relax' or 'norelax'
+# CHECK: warning: unknown option, expected 'push', 'pop', 'rvc', 'norvc', 'relax' or 'norelax'
.option bar
+
+# CHECK: error: .option pop with no .option push
+.option pop
+
+# CHECK: error: unexpected token, expected end of statement
+.option push 123
+
+# CHECK: error: unexpected token, expected end of statement
+.option pop 123
diff --git a/llvm/test/MC/RISCV/option-pushpop.s b/llvm/test/MC/RISCV/option-pushpop.s
new file mode 100644
index 00000000000..9e3ae4156a4
--- /dev/null
+++ b/llvm/test/MC/RISCV/option-pushpop.s
@@ -0,0 +1,74 @@
+# RUN: llvm-mc -triple riscv32 -mattr=-relax -riscv-no-aliases < %s \
+# RUN: | FileCheck -check-prefix=CHECK-INST %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \
+# RUN: | llvm-readobj -r | FileCheck -check-prefix=CHECK-RELOC %s
+# RUN: llvm-mc -triple riscv32 -filetype=obj < %s \
+# RUN: | llvm-objdump -triple riscv32 -mattr=+c -d - \
+# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
+
+# RUN: llvm-mc -triple riscv64 -mattr=-relax -riscv-no-aliases < %s \
+# RUN: | FileCheck -check-prefix=CHECK-INST %s
+# RUN: llvm-mc -filetype=obj -triple riscv64 < %s \
+# RUN: | llvm-readobj -r | FileCheck -check-prefix=CHECK-RELOC %s
+# RUN: llvm-mc -triple riscv64 -filetype=obj < %s \
+# RUN: | llvm-objdump -triple riscv64 -mattr=+c -d - \
+# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
+
+# Test the operation of the push and pop assembler directives when
+# using .option relax and .option rvc. Checks that using .option pop
+# correctly restores all target features to their state at the point
+# where .option pop was last used.
+
+# CHECK-INST: call foo
+# CHECK-RELOC: R_RISCV_CALL foo 0x0
+# CHECK-RELOC-NOT: R_RISCV_RELAX foo 0x0
+call foo
+
+# CHECK-INST: addi s0, sp, 1020
+# CHECK-BYTES: 13 04 c1 3f
+# CHECK-ALIAS: addi s0, sp, 1020
+addi s0, sp, 1020
+
+.option push # Push relax=false, rvc=false
+# CHECK-INST: .option push
+
+.option relax
+# CHECK-INST: .option relax
+# CHECK-INST: call bar
+# CHECK-RELOC-NEXT: R_RISCV_CALL bar 0x0
+# CHECK-RELOC-NEXT: R_RISCV_RELAX bar 0x0
+call bar
+
+.option push # Push relax=true, rvc=false
+# CHECK-INST: .option push
+
+.option rvc
+# CHECK-INST: .option rvc
+# CHECK-INST: c.addi4spn s0, sp, 1020
+# CHECK-BYTES: e0 1f
+# CHECK-ALIAS: addi s0, sp, 1020
+addi s0, sp, 1020
+
+.option pop # Pop relax=true, rvc=false
+# CHECK-INST: .option pop
+# CHECK-INST: addi s0, sp, 1020
+# CHECK-BYTES: 13 04 c1 3f
+# CHECK-ALIAS: addi s0, sp, 1020
+addi s0, sp, 1020
+
+# CHECK-INST: call bar
+# CHECK-RELOC-NEXT: R_RISCV_CALL bar 0x0
+# CHECK-RELOC-NEXT: R_RISCV_RELAX bar 0x0
+call bar
+
+.option pop # Pop relax=false, rvc=false
+# CHECK-INST: .option pop
+# CHECK-INST: call baz
+# CHECK-RELOC: R_RISCV_CALL baz 0x0
+# CHECK-RELOC-NOT: R_RISCV_RELAX baz 0x0
+call baz
+
+# CHECK-INST: addi s0, sp, 1020
+# CHECK-BYTES: 13 04 c1 3f
+# CHECK-ALIAS: addi s0, sp, 1020
+addi s0, sp, 1020
OpenPOWER on IntegriCloud