[llvm] [LoongArch] Support .option directive (PR #110404)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 28 21:09:34 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-loongarch
Author: wanglei (wangleiat)
<details>
<summary>Changes</summary>
The .option can accept 4 parameters like the LoongArch's gnu as:
push, pop, relax and norelax.
---
Full diff: https://github.com/llvm/llvm-project/pull/110404.diff
8 Files Affected:
- (modified) llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp (+108)
- (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.cpp (+5)
- (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.h (+5)
- (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp (+8)
- (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.cpp (+26)
- (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.h (+19)
- (added) llvm/test/MC/LoongArch/Directives/option-pushpop.s (+59)
- (added) llvm/test/MC/LoongArch/Directives/option-relax.s (+30)
``````````diff
diff --git a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
index 57c42024b4d2b2..d9752e7951a951 100644
--- a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
+++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
@@ -10,6 +10,7 @@
#include "MCTargetDesc/LoongArchMCExpr.h"
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
#include "MCTargetDesc/LoongArchMatInt.h"
+#include "MCTargetDesc/LoongArchTargetStreamer.h"
#include "TargetInfo/LoongArchTargetInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstBuilder.h"
@@ -30,8 +31,16 @@ using namespace llvm;
namespace {
class LoongArchAsmParser : public MCTargetAsmParser {
+ SmallVector<FeatureBitset, 4> FeatureBitStack;
+
SMLoc getLoc() const { return getParser().getTok().getLoc(); }
bool is64Bit() const { return getSTI().hasFeature(LoongArch::Feature64Bit); }
+ LoongArchTargetStreamer &getTargetStreamer() {
+ assert(getParser().getStreamer().getTargetStreamer() &&
+ "do not have a target streamer");
+ MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
+ return static_cast<LoongArchTargetStreamer &>(TS);
+ }
struct Inst {
unsigned Opc;
@@ -60,6 +69,8 @@ class LoongArchAsmParser : public MCTargetAsmParser {
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
unsigned Kind) override;
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
+
bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
int64_t Lower, int64_t Upper,
const Twine &Msg);
@@ -81,6 +92,39 @@ class LoongArchAsmParser : public MCTargetAsmParser {
bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
+ bool parseDirectiveOption();
+
+ void setFeatureBits(uint64_t Feature, StringRef FeatureString) {
+ if (!(getSTI().hasFeature(Feature))) {
+ MCSubtargetInfo &STI = copySTI();
+ setAvailableFeatures(
+ ComputeAvailableFeatures(STI.ToggleFeature(FeatureString)));
+ }
+ }
+
+ void clearFeatureBits(uint64_t Feature, StringRef FeatureString) {
+ if (getSTI().hasFeature(Feature)) {
+ MCSubtargetInfo &STI = copySTI();
+ setAvailableFeatures(
+ ComputeAvailableFeatures(STI.ToggleFeature(FeatureString)));
+ }
+ }
+
+ 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;
+ }
+
// Helper to emit the sequence of instructions generated by the
// "emitLoadAddress*" functions.
void emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
@@ -1748,6 +1792,70 @@ bool LoongArchAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
llvm_unreachable("Unknown match type detected!");
}
+bool LoongArchAsmParser::parseDirectiveOption() {
+ MCAsmParser &Parser = getParser();
+ // Get the option token.
+ AsmToken Tok = Parser.getTok();
+
+ // At the moment only identifiers are supported.
+ if (parseToken(AsmToken::Identifier, "expected identifier"))
+ return true;
+
+ StringRef Option = Tok.getIdentifier();
+
+ if (Option == "push") {
+ if (Parser.parseEOL())
+ return true;
+
+ getTargetStreamer().emitDirectiveOptionPush();
+ pushFeatureBits();
+ return false;
+ }
+
+ if (Option == "pop") {
+ SMLoc StartLoc = Parser.getTok().getLoc();
+ if (Parser.parseEOL())
+ return true;
+
+ getTargetStreamer().emitDirectiveOptionPop();
+ if (popFeatureBits())
+ return Error(StartLoc, ".option pop with no .option push");
+
+ return false;
+ }
+
+ if (Option == "relax") {
+ if (Parser.parseEOL())
+ return true;
+
+ getTargetStreamer().emitDirectiveOptionRelax();
+ setFeatureBits(LoongArch::FeatureRelax, "relax");
+ return false;
+ }
+
+ if (Option == "norelax") {
+ if (Parser.parseEOL())
+ return true;
+
+ getTargetStreamer().emitDirectiveOptionNoRelax();
+ clearFeatureBits(LoongArch::FeatureRelax, "relax");
+ return false;
+ }
+
+ // Unknown option.
+ Warning(Parser.getTok().getLoc(),
+ "unknown option, expected 'push', 'pop', 'relax' or 'norelax'");
+ Parser.eatToEndOfStatement();
+ return false;
+}
+
+ParseStatus LoongArchAsmParser::parseDirective(AsmToken DirectiveID) {
+ if (DirectiveID.getString() == ".option")
+ return parseDirectiveOption();
+
+ return ParseStatus::NoMatch;
+}
+
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() {
RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target());
RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target());
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.cpp
index eee85822398b14..f2900797c6a2be 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.cpp
@@ -35,6 +35,11 @@ MCELFStreamer &LoongArchTargetELFStreamer::getStreamer() {
return static_cast<MCELFStreamer &>(Streamer);
}
+void LoongArchTargetELFStreamer::emitDirectiveOptionPush() {}
+void LoongArchTargetELFStreamer::emitDirectiveOptionPop() {}
+void LoongArchTargetELFStreamer::emitDirectiveOptionRelax() {}
+void LoongArchTargetELFStreamer::emitDirectiveOptionNoRelax() {}
+
void LoongArchTargetELFStreamer::finish() {
LoongArchTargetStreamer::finish();
ELFObjectWriter &W = getStreamer().getWriter();
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.h
index e220729d8923e2..894ea963071487 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.h
@@ -19,6 +19,11 @@ class LoongArchTargetELFStreamer : public LoongArchTargetStreamer {
MCELFStreamer &getStreamer();
LoongArchTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
+ void emitDirectiveOptionPush() override;
+ void emitDirectiveOptionPop() override;
+ void emitDirectiveOptionRelax() override;
+ void emitDirectiveOptionNoRelax() override;
+
void finish() override;
};
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp
index 595ce9fc815bf0..62e900dc65babb 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp
@@ -87,6 +87,12 @@ createLoongArchObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
: nullptr;
}
+static MCTargetStreamer *
+createLoongArchAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS,
+ MCInstPrinter *InstPrint) {
+ return new LoongArchTargetAsmStreamer(S, OS);
+}
+
namespace {
class LoongArchMCInstrAnalysis : public MCInstrAnalysis {
@@ -212,5 +218,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchTargetMC() {
TargetRegistry::RegisterELFStreamer(*T, createLoongArchELFStreamer);
TargetRegistry::RegisterObjectTargetStreamer(
*T, createLoongArchObjectTargetStreamer);
+ TargetRegistry::RegisterAsmTargetStreamer(*T,
+ createLoongArchAsmTargetStreamer);
}
}
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.cpp
index 57117844205519..8f9f0cb593b93b 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.cpp
@@ -22,3 +22,29 @@ void LoongArchTargetStreamer::setTargetABI(LoongArchABI::ABI ABI) {
"Improperly initialized target ABI");
TargetABI = ABI;
}
+
+void LoongArchTargetStreamer::emitDirectiveOptionPush() {}
+void LoongArchTargetStreamer::emitDirectiveOptionPop() {}
+void LoongArchTargetStreamer::emitDirectiveOptionRelax() {}
+void LoongArchTargetStreamer::emitDirectiveOptionNoRelax() {}
+
+// This part is for ascii assembly output.
+LoongArchTargetAsmStreamer::LoongArchTargetAsmStreamer(
+ MCStreamer &S, formatted_raw_ostream &OS)
+ : LoongArchTargetStreamer(S), OS(OS) {}
+
+void LoongArchTargetAsmStreamer::emitDirectiveOptionPush() {
+ OS << "\t.option\tpush\n";
+}
+
+void LoongArchTargetAsmStreamer::emitDirectiveOptionPop() {
+ OS << "\t.option\tpop\n";
+}
+
+void LoongArchTargetAsmStreamer::emitDirectiveOptionRelax() {
+ OS << "\t.option\trelax\n";
+}
+
+void LoongArchTargetAsmStreamer::emitDirectiveOptionNoRelax() {
+ OS << "\t.option\tnorelax\n";
+}
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.h
index d4b1b2a3e358db..96c324a3b6dc3c 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.h
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.h
@@ -12,6 +12,7 @@
#include "LoongArch.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/FormattedStream.h"
namespace llvm {
class LoongArchTargetStreamer : public MCTargetStreamer {
@@ -21,6 +22,24 @@ class LoongArchTargetStreamer : public MCTargetStreamer {
LoongArchTargetStreamer(MCStreamer &S);
void setTargetABI(LoongArchABI::ABI ABI);
LoongArchABI::ABI getTargetABI() const { return TargetABI; }
+
+ virtual void emitDirectiveOptionPush();
+ virtual void emitDirectiveOptionPop();
+ virtual void emitDirectiveOptionRelax();
+ virtual void emitDirectiveOptionNoRelax();
+};
+
+// This part is for ascii assembly output.
+class LoongArchTargetAsmStreamer : public LoongArchTargetStreamer {
+ formatted_raw_ostream &OS;
+
+public:
+ LoongArchTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
+
+ void emitDirectiveOptionPush() override;
+ void emitDirectiveOptionPop() override;
+ void emitDirectiveOptionRelax() override;
+ void emitDirectiveOptionNoRelax() override;
};
} // end namespace llvm
diff --git a/llvm/test/MC/LoongArch/Directives/option-pushpop.s b/llvm/test/MC/LoongArch/Directives/option-pushpop.s
new file mode 100644
index 00000000000000..fbc7ea09b2fe72
--- /dev/null
+++ b/llvm/test/MC/LoongArch/Directives/option-pushpop.s
@@ -0,0 +1,59 @@
+# RUN: llvm-mc --triple loongarch64 --mattr=-relax < %s \
+# RUN: | FileCheck --check-prefix=CHECK-ASM %s
+# RUN: llvm-mc --triple loongarch64 --filetype=obj < %s \
+# RUN: | llvm-readobj -r - | FileCheck --check-prefix=CHECK-RELOC %s
+
+# Test the operation of the push and pop assembler directives when
+# using .option relax. Checks that using .option pop correctly restores
+# all target features to their state at the point where .option pop was
+# last used.
+
+# CHECK-ASM: .option push
+.option push # relax = false
+
+# CHECK-ASM: .option relax
+.option relax # relax = true
+
+# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym1)
+# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym1)
+# CHECK-RELOC: R_LARCH_PCALA_HI20 sym1 0x0
+# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
+# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym1 0x0
+# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
+la.pcrel $a0, sym1
+
+# CHECK-ASM: .option push
+.option push # relax = true
+
+# CHECK-ASM: .option norelax
+.option norelax # relax = false
+
+# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym2)
+# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym2)
+# CHECK-RELOC-NEXT: R_LARCH_PCALA_HI20 sym2 0x0
+# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
+# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym2 0x0
+# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
+la.pcrel $a0, sym2
+
+# CHECK-ASM: .option pop
+.option pop # relax = true
+
+# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym3)
+# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym3)
+# CHECK-RELOC: R_LARCH_PCALA_HI20 sym3 0x0
+# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
+# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym3 0x0
+# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
+la.pcrel $a0, sym3
+
+# CHECK-ASM: .option pop
+.option pop # relax = false
+
+la.pcrel $a0, sym4
+# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym4)
+# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym4)
+# CHECK-RELOC-NEXT: R_LARCH_PCALA_HI20 sym4 0x0
+# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
+# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym4 0x0
+# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
diff --git a/llvm/test/MC/LoongArch/Directives/option-relax.s b/llvm/test/MC/LoongArch/Directives/option-relax.s
new file mode 100644
index 00000000000000..e016e47156d39e
--- /dev/null
+++ b/llvm/test/MC/LoongArch/Directives/option-relax.s
@@ -0,0 +1,30 @@
+# RUN: llvm-mc --triple loongarch64 < %s | FileCheck --check-prefix=CHECK-ASM %s
+# RUN: llvm-mc -filetype=obj --triple loongarch64 < %s \
+# RUN: | llvm-readobj -r - | FileCheck -check-prefix=CHECK-RELOC %s
+
+# Check .option relax causes R_LARCH_RELAX to be emitted, and .option
+# norelax suppresses it.
+
+# CHECK-ASM: .option relax
+.option relax
+
+# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym1)
+# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym1)
+
+# CHECK-RELOC: R_LARCH_PCALA_HI20 sym1 0x0
+# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
+# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym1 0x0
+# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
+la.pcrel $a0, sym1
+
+# CHECK-ASM: .option norelax
+.option norelax
+
+# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym2)
+# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym2)
+
+# CHECK-RELOC-NEXT: R_LARCH_PCALA_HI20 sym2 0x0
+# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
+# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym2 0x0
+# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
+la.pcrel $a0, sym2
``````````
</details>
https://github.com/llvm/llvm-project/pull/110404
More information about the llvm-commits
mailing list