Skip to content

Commit 6a371c7

Browse files
authored
[RISCV] Support .option {no}exact (#122483)
This implements [the `.option exact` and `.option noexact` proposal](riscv-non-isa/riscv-asm-manual#122) for RISC-V. `.option exact` turns off: - Compression - Branch Relaxation - Linker Relaxation `.option noexact` turns these back on, and is also the default, matching the current behaviour.
1 parent 27539c3 commit 6a371c7

File tree

13 files changed

+265
-59
lines changed

13 files changed

+265
-59
lines changed

llvm/docs/ReleaseNotes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ Changes to the RISC-V Backend
152152
handlers.
153153
* When the experimental extension `Xqcili` is enabled, `qc.e.li` and `qc.li` may
154154
now be used to materialize immediates.
155+
* Adds assembler support for ``.option exact``, which disables automatic compression,
156+
and branch and linker relaxation. This can be disabled with ``.option noexact``,
157+
which is also the default.
155158

156159
Changes to the WebAssembly Backend
157160
----------------------------------

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3205,6 +3205,26 @@ bool RISCVAsmParser::parseDirectiveOption() {
32053205
return false;
32063206
}
32073207

3208+
if (Option == "exact") {
3209+
if (Parser.parseEOL())
3210+
return true;
3211+
3212+
getTargetStreamer().emitDirectiveOptionExact();
3213+
setFeatureBits(RISCV::FeatureExactAssembly, "exact-asm");
3214+
clearFeatureBits(RISCV::FeatureRelax, "relax");
3215+
return false;
3216+
}
3217+
3218+
if (Option == "noexact") {
3219+
if (Parser.parseEOL())
3220+
return true;
3221+
3222+
getTargetStreamer().emitDirectiveOptionNoExact();
3223+
clearFeatureBits(RISCV::FeatureExactAssembly, "exact-asm");
3224+
setFeatureBits(RISCV::FeatureRelax, "relax");
3225+
return false;
3226+
}
3227+
32083228
if (Option == "rvc") {
32093229
if (Parser.parseEOL())
32103230
return true;
@@ -3261,9 +3281,10 @@ bool RISCVAsmParser::parseDirectiveOption() {
32613281
}
32623282

32633283
// Unknown option.
3264-
Warning(Parser.getTok().getLoc(), "unknown option, expected 'push', 'pop', "
3265-
"'rvc', 'norvc', 'arch', 'relax' or "
3266-
"'norelax'");
3284+
Warning(Parser.getTok().getLoc(),
3285+
"unknown option, expected 'push', 'pop', "
3286+
"'rvc', 'norvc', 'arch', 'relax', 'norelax', "
3287+
"'exact', or 'noexact'");
32673288
Parser.eatToEndOfStatement();
32683289
return false;
32693290
}
@@ -3473,10 +3494,13 @@ bool RISCVAsmParser::parseDirectiveVariantCC() {
34733494

34743495
void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) {
34753496
MCInst CInst;
3476-
bool Res = RISCVRVC::compress(CInst, Inst, getSTI());
3497+
bool Res = false;
3498+
const MCSubtargetInfo &STI = getSTI();
3499+
if (!STI.hasFeature(RISCV::FeatureExactAssembly))
3500+
Res = RISCVRVC::compress(CInst, Inst, STI);
34773501
if (Res)
34783502
++RISCVNumInstrsCompressed;
3479-
S.emitInstruction((Res ? CInst : Inst), getSTI());
3503+
S.emitInstruction((Res ? CInst : Inst), STI);
34803504
}
34813505

34823506
void RISCVAsmParser::emitLoadImm(MCRegister DestReg, int64_t Value,

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,39 @@ bool RISCVAsmBackend::fixupNeedsRelaxationAdvanced(
171171
}
172172
}
173173

174+
// Given a compressed control flow instruction this function returns
175+
// the expanded instruction.
176+
static unsigned getRelaxedOpcode(unsigned Op) {
177+
switch (Op) {
178+
default:
179+
return Op;
180+
case RISCV::C_BEQZ:
181+
return RISCV::BEQ;
182+
case RISCV::C_BNEZ:
183+
return RISCV::BNE;
184+
case RISCV::C_J:
185+
case RISCV::C_JAL: // fall through.
186+
return RISCV::JAL;
187+
case RISCV::BEQ:
188+
return RISCV::PseudoLongBEQ;
189+
case RISCV::BNE:
190+
return RISCV::PseudoLongBNE;
191+
case RISCV::BLT:
192+
return RISCV::PseudoLongBLT;
193+
case RISCV::BGE:
194+
return RISCV::PseudoLongBGE;
195+
case RISCV::BLTU:
196+
return RISCV::PseudoLongBLTU;
197+
case RISCV::BGEU:
198+
return RISCV::PseudoLongBGEU;
199+
}
200+
}
201+
174202
void RISCVAsmBackend::relaxInstruction(MCInst &Inst,
175203
const MCSubtargetInfo &STI) const {
204+
if (STI.hasFeature(RISCV::FeatureExactAssembly))
205+
return;
206+
176207
MCInst Res;
177208
switch (Inst.getOpcode()) {
178209
default:
@@ -341,36 +372,14 @@ std::pair<bool, bool> RISCVAsmBackend::relaxLEB128(const MCAssembler &Asm,
341372
return std::make_pair(Expr.evaluateKnownAbsolute(Value, Asm), false);
342373
}
343374

344-
// Given a compressed control flow instruction this function returns
345-
// the expanded instruction.
346-
unsigned RISCVAsmBackend::getRelaxedOpcode(unsigned Op) const {
347-
switch (Op) {
348-
default:
349-
return Op;
350-
case RISCV::C_BEQZ:
351-
return RISCV::BEQ;
352-
case RISCV::C_BNEZ:
353-
return RISCV::BNE;
354-
case RISCV::C_J:
355-
case RISCV::C_JAL: // fall through.
356-
return RISCV::JAL;
357-
case RISCV::BEQ:
358-
return RISCV::PseudoLongBEQ;
359-
case RISCV::BNE:
360-
return RISCV::PseudoLongBNE;
361-
case RISCV::BLT:
362-
return RISCV::PseudoLongBLT;
363-
case RISCV::BGE:
364-
return RISCV::PseudoLongBGE;
365-
case RISCV::BLTU:
366-
return RISCV::PseudoLongBLTU;
367-
case RISCV::BGEU:
368-
return RISCV::PseudoLongBGEU;
369-
}
370-
}
371-
372375
bool RISCVAsmBackend::mayNeedRelaxation(const MCInst &Inst,
373376
const MCSubtargetInfo &STI) const {
377+
// This function has access to two STIs, the member of the AsmBackend, and the
378+
// one passed as an argument. The latter is more specific, so we query it for
379+
// specific features.
380+
if (STI.hasFeature(RISCV::FeatureExactAssembly))
381+
return false;
382+
374383
return getRelaxedOpcode(Inst.getOpcode()) != Inst.getOpcode();
375384
}
376385

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ class RISCVAsmBackend : public MCAsmBackend {
8181

8282
bool mayNeedRelaxation(const MCInst &Inst,
8383
const MCSubtargetInfo &STI) const override;
84-
unsigned getRelaxedOpcode(unsigned Op) const;
8584

8685
void relaxInstruction(MCInst &Inst,
8786
const MCSubtargetInfo &STI) const override;

llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,16 @@ RISCVELFStreamer &RISCVTargetELFStreamer::getStreamer() {
4747
return static_cast<RISCVELFStreamer &>(Streamer);
4848
}
4949

50-
void RISCVTargetELFStreamer::emitDirectiveOptionPush() {}
51-
void RISCVTargetELFStreamer::emitDirectiveOptionPop() {}
50+
void RISCVTargetELFStreamer::emitDirectiveOptionExact() {}
51+
void RISCVTargetELFStreamer::emitDirectiveOptionNoExact() {}
5252
void RISCVTargetELFStreamer::emitDirectiveOptionPIC() {}
5353
void RISCVTargetELFStreamer::emitDirectiveOptionNoPIC() {}
54-
void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {}
55-
void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {}
54+
void RISCVTargetELFStreamer::emitDirectiveOptionPop() {}
55+
void RISCVTargetELFStreamer::emitDirectiveOptionPush() {}
5656
void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {}
5757
void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() {}
58+
void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {}
59+
void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {}
5860

5961
void RISCVTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
6062
getStreamer().setAttributeItem(Attribute, Value, /*OverwriteExisting=*/true);

llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,16 @@ class RISCVTargetELFStreamer : public RISCVTargetStreamer {
5656
RISCVELFStreamer &getStreamer();
5757
RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
5858

59-
void emitDirectiveOptionPush() override;
60-
void emitDirectiveOptionPop() override;
59+
void emitDirectiveOptionExact() override;
60+
void emitDirectiveOptionNoExact() override;
6161
void emitDirectiveOptionPIC() override;
6262
void emitDirectiveOptionNoPIC() override;
63-
void emitDirectiveOptionRVC() override;
64-
void emitDirectiveOptionNoRVC() override;
63+
void emitDirectiveOptionPop() override;
64+
void emitDirectiveOptionPush() override;
6565
void emitDirectiveOptionRelax() override;
6666
void emitDirectiveOptionNoRelax() override;
67+
void emitDirectiveOptionRVC() override;
68+
void emitDirectiveOptionNoRVC() override;
6769
void emitDirectiveVariantCC(MCSymbol &Symbol) override;
6870

6971
void finish() override;

llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,18 @@ RISCVTargetStreamer::RISCVTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
3333
void RISCVTargetStreamer::finish() { finishAttributeSection(); }
3434
void RISCVTargetStreamer::reset() {}
3535

36-
void RISCVTargetStreamer::emitDirectiveOptionPush() {}
37-
void RISCVTargetStreamer::emitDirectiveOptionPop() {}
36+
void RISCVTargetStreamer::emitDirectiveOptionArch(
37+
ArrayRef<RISCVOptionArchArg> Args) {}
38+
void RISCVTargetStreamer::emitDirectiveOptionExact() {}
39+
void RISCVTargetStreamer::emitDirectiveOptionNoExact() {}
3840
void RISCVTargetStreamer::emitDirectiveOptionPIC() {}
3941
void RISCVTargetStreamer::emitDirectiveOptionNoPIC() {}
40-
void RISCVTargetStreamer::emitDirectiveOptionRVC() {}
41-
void RISCVTargetStreamer::emitDirectiveOptionNoRVC() {}
42+
void RISCVTargetStreamer::emitDirectiveOptionPop() {}
43+
void RISCVTargetStreamer::emitDirectiveOptionPush() {}
4244
void RISCVTargetStreamer::emitDirectiveOptionRelax() {}
4345
void RISCVTargetStreamer::emitDirectiveOptionNoRelax() {}
44-
void RISCVTargetStreamer::emitDirectiveOptionArch(
45-
ArrayRef<RISCVOptionArchArg> Args) {}
46+
void RISCVTargetStreamer::emitDirectiveOptionRVC() {}
47+
void RISCVTargetStreamer::emitDirectiveOptionNoRVC() {}
4648
void RISCVTargetStreamer::emitDirectiveVariantCC(MCSymbol &Symbol) {}
4749
void RISCVTargetStreamer::emitAttribute(unsigned Attribute, unsigned Value) {}
4850
void RISCVTargetStreamer::finishAttributeSection() {}
@@ -125,6 +127,14 @@ void RISCVTargetAsmStreamer::emitDirectiveOptionNoRVC() {
125127
OS << "\t.option\tnorvc\n";
126128
}
127129

130+
void RISCVTargetAsmStreamer::emitDirectiveOptionExact() {
131+
OS << "\t.option\texact\n";
132+
}
133+
134+
void RISCVTargetAsmStreamer::emitDirectiveOptionNoExact() {
135+
OS << "\t.option\tnoexact\n";
136+
}
137+
128138
void RISCVTargetAsmStreamer::emitDirectiveOptionRelax() {
129139
OS << "\t.option\trelax\n";
130140
}

llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,17 @@ class RISCVTargetStreamer : public MCTargetStreamer {
4141
void finish() override;
4242
virtual void reset();
4343

44-
virtual void emitDirectiveOptionPush();
45-
virtual void emitDirectiveOptionPop();
44+
virtual void emitDirectiveOptionArch(ArrayRef<RISCVOptionArchArg> Args);
45+
virtual void emitDirectiveOptionExact();
46+
virtual void emitDirectiveOptionNoExact();
4647
virtual void emitDirectiveOptionPIC();
4748
virtual void emitDirectiveOptionNoPIC();
48-
virtual void emitDirectiveOptionRVC();
49-
virtual void emitDirectiveOptionNoRVC();
49+
virtual void emitDirectiveOptionPop();
50+
virtual void emitDirectiveOptionPush();
5051
virtual void emitDirectiveOptionRelax();
5152
virtual void emitDirectiveOptionNoRelax();
52-
virtual void emitDirectiveOptionArch(ArrayRef<RISCVOptionArchArg> Args);
53+
virtual void emitDirectiveOptionRVC();
54+
virtual void emitDirectiveOptionNoRVC();
5355
virtual void emitDirectiveVariantCC(MCSymbol &Symbol);
5456
virtual void emitAttribute(unsigned Attribute, unsigned Value);
5557
virtual void finishAttributeSection();
@@ -78,15 +80,17 @@ class RISCVTargetAsmStreamer : public RISCVTargetStreamer {
7880
public:
7981
RISCVTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
8082

81-
void emitDirectiveOptionPush() override;
82-
void emitDirectiveOptionPop() override;
83+
void emitDirectiveOptionArch(ArrayRef<RISCVOptionArchArg> Args) override;
84+
void emitDirectiveOptionExact() override;
85+
void emitDirectiveOptionNoExact() override;
8386
void emitDirectiveOptionPIC() override;
8487
void emitDirectiveOptionNoPIC() override;
85-
void emitDirectiveOptionRVC() override;
86-
void emitDirectiveOptionNoRVC() override;
88+
void emitDirectiveOptionPop() override;
89+
void emitDirectiveOptionPush() override;
8790
void emitDirectiveOptionRelax() override;
8891
void emitDirectiveOptionNoRelax() override;
89-
void emitDirectiveOptionArch(ArrayRef<RISCVOptionArchArg> Args) override;
92+
void emitDirectiveOptionRVC() override;
93+
void emitDirectiveOptionNoRVC() override;
9094
void emitDirectiveVariantCC(MCSymbol &Symbol) override;
9195
};
9296

llvm/lib/Target/RISCV/RISCVFeatures.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,10 @@ def FeatureRelax
14961496
: SubtargetFeature<"relax", "EnableLinkerRelax", "true",
14971497
"Enable Linker relaxation.">;
14981498

1499+
def FeatureExactAssembly
1500+
: SubtargetFeature<"exact-asm", "EnableExactAssembly", "true",
1501+
"Enable Exact Assembly (Disables Compression and Relaxation)">;
1502+
14991503
foreach i = {1-31} in
15001504
def FeatureReserveX#i :
15011505
SubtargetFeature<"reserve-x"#i, "UserReservedRegister[RISCV::X"#i#"]",

llvm/test/CodeGen/RISCV/features-info.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
; CHECK-NEXT: disable-latency-sched-heuristic - Disable latency scheduling heuristic.
1515
; CHECK-NEXT: dlen-factor-2 - Vector unit DLEN(data path width) is half of VLEN.
1616
; CHECK-NEXT: e - 'E' (Embedded Instruction Set with 16 GPRs).
17+
; CHECK-NEXT: exact-asm - Enable Exact Assembly (Disables Compression and Relaxation).
1718
; CHECK-NEXT: experimental - Experimental intrinsics.
1819
; CHECK-NEXT: experimental-p - 'P' ('Base P' (Packed SIMD)).
1920
; CHECK-NEXT: experimental-rvm23u32 - RISC-V experimental-rvm23u32 profile.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
; RUN: llc -mtriple=riscv32 -mattr=+relax,+c %s --filetype=obj -o - \
2+
; RUN: | llvm-objdump --triple=riscv32 --mattr=+c -M no-aliases -dr - \
3+
; RUN: | FileCheck %s
4+
5+
define i32 @foo(ptr noundef %f) nounwind {
6+
; CHECK-LABEL: <foo>:
7+
; CHECK: auipc ra, 0x0
8+
; CHECK-NEXT: R_RISCV_CALL_PLT undefined
9+
; CHECK-NEXT: jalr ra, 0x0(ra)
10+
; CHECK-NEXT: lw a0, 0x0(a0)
11+
; CHECK-NEXT: c.jr ra
12+
13+
entry:
14+
%0 = tail call i32 asm sideeffect "
15+
.option exact
16+
call undefined@plt
17+
lw $0, ($1)
18+
.option noexact", "=^cr,^cr"(ptr %f)
19+
ret i32 %0
20+
}

0 commit comments

Comments
 (0)