Skip to content

Commit 1a787b3

Browse files
authored
[LoongArch] Support .option directive
The .option can accept 4 parameters like the LoongArch's gnu as: push, pop, relax and norelax. Reviewed By: heiher, SixWeining Pull Request: #110404
1 parent dba54fb commit 1a787b3

File tree

9 files changed

+283
-0
lines changed

9 files changed

+283
-0
lines changed

llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "MCTargetDesc/LoongArchMCExpr.h"
1111
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
1212
#include "MCTargetDesc/LoongArchMatInt.h"
13+
#include "MCTargetDesc/LoongArchTargetStreamer.h"
1314
#include "TargetInfo/LoongArchTargetInfo.h"
1415
#include "llvm/MC/MCContext.h"
1516
#include "llvm/MC/MCInstBuilder.h"
@@ -30,8 +31,16 @@ using namespace llvm;
3031

3132
namespace {
3233
class LoongArchAsmParser : public MCTargetAsmParser {
34+
SmallVector<FeatureBitset, 4> FeatureBitStack;
35+
3336
SMLoc getLoc() const { return getParser().getTok().getLoc(); }
3437
bool is64Bit() const { return getSTI().hasFeature(LoongArch::Feature64Bit); }
38+
LoongArchTargetStreamer &getTargetStreamer() {
39+
assert(getParser().getStreamer().getTargetStreamer() &&
40+
"do not have a target streamer");
41+
MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
42+
return static_cast<LoongArchTargetStreamer &>(TS);
43+
}
3544

3645
struct Inst {
3746
unsigned Opc;
@@ -60,6 +69,8 @@ class LoongArchAsmParser : public MCTargetAsmParser {
6069
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
6170
unsigned Kind) override;
6271

72+
ParseStatus parseDirective(AsmToken DirectiveID) override;
73+
6374
bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
6475
int64_t Lower, int64_t Upper,
6576
const Twine &Msg);
@@ -81,6 +92,39 @@ class LoongArchAsmParser : public MCTargetAsmParser {
8192

8293
bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
8394

95+
bool parseDirectiveOption();
96+
97+
void setFeatureBits(uint64_t Feature, StringRef FeatureString) {
98+
if (!(getSTI().hasFeature(Feature))) {
99+
MCSubtargetInfo &STI = copySTI();
100+
setAvailableFeatures(
101+
ComputeAvailableFeatures(STI.ToggleFeature(FeatureString)));
102+
}
103+
}
104+
105+
void clearFeatureBits(uint64_t Feature, StringRef FeatureString) {
106+
if (getSTI().hasFeature(Feature)) {
107+
MCSubtargetInfo &STI = copySTI();
108+
setAvailableFeatures(
109+
ComputeAvailableFeatures(STI.ToggleFeature(FeatureString)));
110+
}
111+
}
112+
113+
void pushFeatureBits() {
114+
FeatureBitStack.push_back(getSTI().getFeatureBits());
115+
}
116+
117+
bool popFeatureBits() {
118+
if (FeatureBitStack.empty())
119+
return true;
120+
121+
FeatureBitset FeatureBits = FeatureBitStack.pop_back_val();
122+
copySTI().setFeatureBits(FeatureBits);
123+
setAvailableFeatures(ComputeAvailableFeatures(FeatureBits));
124+
125+
return false;
126+
}
127+
84128
// Helper to emit the sequence of instructions generated by the
85129
// "emitLoadAddress*" functions.
86130
void emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
@@ -1748,6 +1792,70 @@ bool LoongArchAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
17481792
llvm_unreachable("Unknown match type detected!");
17491793
}
17501794

1795+
bool LoongArchAsmParser::parseDirectiveOption() {
1796+
MCAsmParser &Parser = getParser();
1797+
// Get the option token.
1798+
AsmToken Tok = Parser.getTok();
1799+
1800+
// At the moment only identifiers are supported.
1801+
if (parseToken(AsmToken::Identifier, "expected identifier"))
1802+
return true;
1803+
1804+
StringRef Option = Tok.getIdentifier();
1805+
1806+
if (Option == "push") {
1807+
if (Parser.parseEOL())
1808+
return true;
1809+
1810+
getTargetStreamer().emitDirectiveOptionPush();
1811+
pushFeatureBits();
1812+
return false;
1813+
}
1814+
1815+
if (Option == "pop") {
1816+
SMLoc StartLoc = Parser.getTok().getLoc();
1817+
if (Parser.parseEOL())
1818+
return true;
1819+
1820+
getTargetStreamer().emitDirectiveOptionPop();
1821+
if (popFeatureBits())
1822+
return Error(StartLoc, ".option pop with no .option push");
1823+
1824+
return false;
1825+
}
1826+
1827+
if (Option == "relax") {
1828+
if (Parser.parseEOL())
1829+
return true;
1830+
1831+
getTargetStreamer().emitDirectiveOptionRelax();
1832+
setFeatureBits(LoongArch::FeatureRelax, "relax");
1833+
return false;
1834+
}
1835+
1836+
if (Option == "norelax") {
1837+
if (Parser.parseEOL())
1838+
return true;
1839+
1840+
getTargetStreamer().emitDirectiveOptionNoRelax();
1841+
clearFeatureBits(LoongArch::FeatureRelax, "relax");
1842+
return false;
1843+
}
1844+
1845+
// Unknown option.
1846+
Warning(Parser.getTok().getLoc(),
1847+
"unknown option, expected 'push', 'pop', 'relax' or 'norelax'");
1848+
Parser.eatToEndOfStatement();
1849+
return false;
1850+
}
1851+
1852+
ParseStatus LoongArchAsmParser::parseDirective(AsmToken DirectiveID) {
1853+
if (DirectiveID.getString() == ".option")
1854+
return parseDirectiveOption();
1855+
1856+
return ParseStatus::NoMatch;
1857+
}
1858+
17511859
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() {
17521860
RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target());
17531861
RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target());

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ MCELFStreamer &LoongArchTargetELFStreamer::getStreamer() {
3535
return static_cast<MCELFStreamer &>(Streamer);
3636
}
3737

38+
void LoongArchTargetELFStreamer::emitDirectiveOptionPush() {}
39+
void LoongArchTargetELFStreamer::emitDirectiveOptionPop() {}
40+
void LoongArchTargetELFStreamer::emitDirectiveOptionRelax() {}
41+
void LoongArchTargetELFStreamer::emitDirectiveOptionNoRelax() {}
42+
3843
void LoongArchTargetELFStreamer::finish() {
3944
LoongArchTargetStreamer::finish();
4045
ELFObjectWriter &W = getStreamer().getWriter();

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFStreamer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ class LoongArchTargetELFStreamer : public LoongArchTargetStreamer {
1919
MCELFStreamer &getStreamer();
2020
LoongArchTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
2121

22+
void emitDirectiveOptionPush() override;
23+
void emitDirectiveOptionPop() override;
24+
void emitDirectiveOptionRelax() override;
25+
void emitDirectiveOptionNoRelax() override;
26+
2227
void finish() override;
2328
};
2429

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ createLoongArchObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
8787
: nullptr;
8888
}
8989

90+
static MCTargetStreamer *
91+
createLoongArchAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS,
92+
MCInstPrinter *InstPrint) {
93+
return new LoongArchTargetAsmStreamer(S, OS);
94+
}
95+
9096
namespace {
9197

9298
class LoongArchMCInstrAnalysis : public MCInstrAnalysis {
@@ -212,5 +218,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchTargetMC() {
212218
TargetRegistry::RegisterELFStreamer(*T, createLoongArchELFStreamer);
213219
TargetRegistry::RegisterObjectTargetStreamer(
214220
*T, createLoongArchObjectTargetStreamer);
221+
TargetRegistry::RegisterAsmTargetStreamer(*T,
222+
createLoongArchAsmTargetStreamer);
215223
}
216224
}

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,29 @@ void LoongArchTargetStreamer::setTargetABI(LoongArchABI::ABI ABI) {
2222
"Improperly initialized target ABI");
2323
TargetABI = ABI;
2424
}
25+
26+
void LoongArchTargetStreamer::emitDirectiveOptionPush() {}
27+
void LoongArchTargetStreamer::emitDirectiveOptionPop() {}
28+
void LoongArchTargetStreamer::emitDirectiveOptionRelax() {}
29+
void LoongArchTargetStreamer::emitDirectiveOptionNoRelax() {}
30+
31+
// This part is for ascii assembly output.
32+
LoongArchTargetAsmStreamer::LoongArchTargetAsmStreamer(
33+
MCStreamer &S, formatted_raw_ostream &OS)
34+
: LoongArchTargetStreamer(S), OS(OS) {}
35+
36+
void LoongArchTargetAsmStreamer::emitDirectiveOptionPush() {
37+
OS << "\t.option\tpush\n";
38+
}
39+
40+
void LoongArchTargetAsmStreamer::emitDirectiveOptionPop() {
41+
OS << "\t.option\tpop\n";
42+
}
43+
44+
void LoongArchTargetAsmStreamer::emitDirectiveOptionRelax() {
45+
OS << "\t.option\trelax\n";
46+
}
47+
48+
void LoongArchTargetAsmStreamer::emitDirectiveOptionNoRelax() {
49+
OS << "\t.option\tnorelax\n";
50+
}

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchTargetStreamer.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "LoongArch.h"
1313
#include "llvm/MC/MCStreamer.h"
1414
#include "llvm/MC/MCSubtargetInfo.h"
15+
#include "llvm/Support/FormattedStream.h"
1516

1617
namespace llvm {
1718
class LoongArchTargetStreamer : public MCTargetStreamer {
@@ -21,6 +22,24 @@ class LoongArchTargetStreamer : public MCTargetStreamer {
2122
LoongArchTargetStreamer(MCStreamer &S);
2223
void setTargetABI(LoongArchABI::ABI ABI);
2324
LoongArchABI::ABI getTargetABI() const { return TargetABI; }
25+
26+
virtual void emitDirectiveOptionPush();
27+
virtual void emitDirectiveOptionPop();
28+
virtual void emitDirectiveOptionRelax();
29+
virtual void emitDirectiveOptionNoRelax();
30+
};
31+
32+
// This part is for ascii assembly output.
33+
class LoongArchTargetAsmStreamer : public LoongArchTargetStreamer {
34+
formatted_raw_ostream &OS;
35+
36+
public:
37+
LoongArchTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
38+
39+
void emitDirectiveOptionPush() override;
40+
void emitDirectiveOptionPop() override;
41+
void emitDirectiveOptionRelax() override;
42+
void emitDirectiveOptionNoRelax() override;
2443
};
2544

2645
} // end namespace llvm
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# RUN: not llvm-mc --triple=loongarch64 %s 2>&1 \
2+
# RUN: | FileCheck --implicit-check-not=error: %s
3+
4+
# CHECK: :[[#@LINE+1]]:8: error: expected identifier
5+
.option
6+
7+
# CHECK: :[[#@LINE+1]]:9: error: expected identifier
8+
.option 123
9+
10+
# CHECK: :[[#@LINE+1]]:9: error: expected identifier
11+
.option "str"
12+
13+
# CHECK: :[[#@LINE+1]]:12: warning: unknown option, expected 'push', 'pop', 'relax' or 'norelax'
14+
.option bar
15+
16+
# CHECK: :[[#@LINE+1]]:12: error: .option pop with no .option push
17+
.option pop
18+
19+
# CHECK: :[[#@LINE+1]]:14: error: expected newline
20+
.option push 123
21+
22+
# CHECK: :[[#@LINE+1]]:13: error: expected newline
23+
.option pop 123
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# RUN: llvm-mc --triple=loongarch64 --mattr=-relax %s \
2+
# RUN: | FileCheck --check-prefix=CHECK-ASM %s
3+
# RUN: llvm-mc --triple=loongarch64 --mattr=-relax --filetype=obj %s \
4+
# RUN: | llvm-readobj -r - | FileCheck --check-prefix=CHECK-RELOC %s
5+
6+
## Test the operation of the push and pop assembler directives when
7+
## using .option relax. Checks that using .option pop correctly restores
8+
## all target features to their state at the point where .option pop was
9+
## last used.
10+
11+
# CHECK-ASM: .option push
12+
.option push # relax = false
13+
14+
# CHECK-ASM: .option relax
15+
.option relax # relax = true
16+
17+
# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym1)
18+
# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym1)
19+
# CHECK-RELOC: R_LARCH_PCALA_HI20 sym1 0x0
20+
# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
21+
# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym1 0x0
22+
# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
23+
la.pcrel $a0, sym1
24+
25+
# CHECK-ASM: .option push
26+
.option push # relax = true
27+
28+
# CHECK-ASM: .option norelax
29+
.option norelax # relax = false
30+
31+
# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym2)
32+
# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym2)
33+
# CHECK-RELOC-NEXT: R_LARCH_PCALA_HI20 sym2 0x0
34+
# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
35+
# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym2 0x0
36+
# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
37+
la.pcrel $a0, sym2
38+
39+
# CHECK-ASM: .option pop
40+
.option pop # relax = true
41+
42+
# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym3)
43+
# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym3)
44+
# CHECK-RELOC: R_LARCH_PCALA_HI20 sym3 0x0
45+
# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
46+
# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym3 0x0
47+
# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
48+
la.pcrel $a0, sym3
49+
50+
# CHECK-ASM: .option pop
51+
.option pop # relax = false
52+
53+
la.pcrel $a0, sym4
54+
# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym4)
55+
# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym4)
56+
# CHECK-RELOC-NEXT: R_LARCH_PCALA_HI20 sym4 0x0
57+
# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
58+
# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym4 0x0
59+
# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# RUN: llvm-mc --triple=loongarch64 %s | FileCheck --check-prefix=CHECK-ASM %s
2+
# RUN: llvm-mc -filetype=obj --triple=loongarch64 %s \
3+
# RUN: | llvm-readobj -r - | FileCheck -check-prefix=CHECK-RELOC %s
4+
5+
## Check .option relax causes R_LARCH_RELAX to be emitted, and .option
6+
## norelax suppresses it.
7+
8+
# CHECK-ASM: .option relax
9+
.option relax
10+
11+
# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym1)
12+
# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym1)
13+
14+
# CHECK-RELOC: R_LARCH_PCALA_HI20 sym1 0x0
15+
# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
16+
# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym1 0x0
17+
# CHECK-RELOC-NEXT: R_LARCH_RELAX - 0x0
18+
la.pcrel $a0, sym1
19+
20+
# CHECK-ASM: .option norelax
21+
.option norelax
22+
23+
# CHECK-ASM: pcalau12i $a0, %pc_hi20(sym2)
24+
# CHECK-ASM-NEXT: addi.d $a0, $a0, %pc_lo12(sym2)
25+
26+
# CHECK-RELOC-NEXT: R_LARCH_PCALA_HI20 sym2 0x0
27+
# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
28+
# CHECK-RELOC-NEXT: R_LARCH_PCALA_LO12 sym2 0x0
29+
# CHECK-RELOC-NOT: R_LARCH_RELAX - 0x0
30+
la.pcrel $a0, sym2

0 commit comments

Comments
 (0)