Skip to content

Commit

Permalink
[RISCV] Support .option rvc and norvc assembler directives
Browse files Browse the repository at this point in the history
These directives allow the 'C' (compressed) extension to be enabled/disabled 
within a single file.

Differential Revision: https://reviews.llvm.org/D45864
Patch by Kito Cheng


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@332107 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
asb committed May 11, 2018
1 parent d2bdcd6 commit 0d10241
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 2 deletions.
78 changes: 77 additions & 1 deletion lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "MCTargetDesc/RISCVBaseInfo.h"
#include "MCTargetDesc/RISCVMCExpr.h"
#include "MCTargetDesc/RISCVMCTargetDesc.h"
#include "MCTargetDesc/RISCVTargetStreamer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCContext.h"
Expand Down Expand Up @@ -37,6 +38,11 @@ class RISCVAsmParser : public MCTargetAsmParser {
SMLoc getLoc() const { return getParser().getTok().getLoc(); }
bool isRV64() const { return getSTI().hasFeature(RISCV::Feature64Bit); }

RISCVTargetStreamer &getTargetStreamer() {
MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
return static_cast<RISCVTargetStreamer &>(TS);
}

unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
unsigned Kind) override;

Expand Down Expand Up @@ -67,6 +73,23 @@ class RISCVAsmParser : public MCTargetAsmParser {

bool parseOperand(OperandVector &Operands, bool ForceImmediate);

bool parseDirectiveOption();

void setFeatureBits(uint64_t Feature, StringRef FeatureString) {
if (!(getSTI().getFeatureBits()[Feature])) {
MCSubtargetInfo &STI = copySTI();
setAvailableFeatures(
ComputeAvailableFeatures(STI.ToggleFeature(FeatureString)));
}
}

void clearFeatureBits(uint64_t Feature, StringRef FeatureString) {
if (getSTI().getFeatureBits()[Feature]) {
MCSubtargetInfo &STI = copySTI();
setAvailableFeatures(
ComputeAvailableFeatures(STI.ToggleFeature(FeatureString)));
}
}
public:
enum RISCVMatchResultTy {
Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
Expand Down Expand Up @@ -984,7 +1007,60 @@ bool RISCVAsmParser::classifySymbolRef(const MCExpr *Expr,
return Kind != RISCVMCExpr::VK_RISCV_Invalid;
}

bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) {
// This returns false if this function recognizes the directive
// regardless of whether it is successfully handles or reports an
// error. Otherwise it returns true to give the generic parser a
// chance at recognizing it.
StringRef IDVal = DirectiveID.getString();

if (IDVal == ".option")
return parseDirectiveOption();

return true;
}

bool RISCVAsmParser::parseDirectiveOption() {
MCAsmParser &Parser = getParser();
// Get the option token.
AsmToken Tok = Parser.getTok();
// At the moment only identifiers are supported.
if (Tok.isNot(AsmToken::Identifier))
return Error(Parser.getTok().getLoc(),
"unexpected token, expected identifier");

StringRef Option = Tok.getIdentifier();

if (Option == "rvc") {
getTargetStreamer().emitDirectiveOptionRVC();

Parser.Lex();
if (Parser.getTok().isNot(AsmToken::EndOfStatement))
return Error(Parser.getTok().getLoc(),
"unexpected token, expected end of statement");

setFeatureBits(RISCV::FeatureStdExtC, "c");
return false;
}

if (Option == "norvc") {
getTargetStreamer().emitDirectiveOptionNoRVC();

Parser.Lex();
if (Parser.getTok().isNot(AsmToken::EndOfStatement))
return Error(Parser.getTok().getLoc(),
"unexpected token, expected end of statement");

clearFeatureBits(RISCV::FeatureStdExtC, "c");
return false;
}

// Unknown option.
Warning(Parser.getTok().getLoc(),
"unknown option, expected 'rvc' or 'norvc'");
Parser.eatToEndOfStatement();
return false;
}

extern "C" void LLVMInitializeRISCVAsmParser() {
RegisterMCAsmParser<RISCVAsmParser> X(getTheRISCV32Target());
Expand Down
3 changes: 3 additions & 0 deletions lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S,
MCELFStreamer &RISCVTargetELFStreamer::getStreamer() {
return static_cast<MCELFStreamer &>(Streamer);
}

void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {}
void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {}
3 changes: 3 additions & 0 deletions lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class RISCVTargetELFStreamer : public RISCVTargetStreamer {
public:
MCELFStreamer &getStreamer();
RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);

virtual void emitDirectiveOptionRVC();
virtual void emitDirectiveOptionNoRVC();
};
}
#endif
12 changes: 11 additions & 1 deletion lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,14 @@ createRISCVObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
const Triple &TT = STI.getTargetTriple();
if (TT.isOSBinFormatELF())
return new RISCVTargetELFStreamer(S, STI);
return new RISCVTargetStreamer(S);
return nullptr;
}

static MCTargetStreamer *createRISCVAsmTargetStreamer(MCStreamer &S,
formatted_raw_ostream &OS,
MCInstPrinter *InstPrint,
bool isVerboseAsm) {
return new RISCVTargetAsmStreamer(S, OS);
}

extern "C" void LLVMInitializeRISCVTargetMC() {
Expand All @@ -88,5 +95,8 @@ extern "C" void LLVMInitializeRISCVTargetMC() {
TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo);
TargetRegistry::RegisterObjectTargetStreamer(
*T, createRISCVObjectTargetStreamer);

// Register the asm target streamer.
TargetRegistry::RegisterAsmTargetStreamer(*T, createRISCVAsmTargetStreamer);
}
}
14 changes: 14 additions & 0 deletions lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,21 @@
//===----------------------------------------------------------------------===//

#include "RISCVTargetStreamer.h"
#include "llvm/Support/FormattedStream.h"

using namespace llvm;

RISCVTargetStreamer::RISCVTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}

// This part is for ascii assembly output
RISCVTargetAsmStreamer::RISCVTargetAsmStreamer(MCStreamer &S,
formatted_raw_ostream &OS)
: RISCVTargetStreamer(S), OS(OS) {}

void RISCVTargetAsmStreamer::emitDirectiveOptionRVC() {
OS << "\t.option\trvc\n";
}

void RISCVTargetAsmStreamer::emitDirectiveOptionNoRVC() {
OS << "\t.option\tnorvc\n";
}
15 changes: 15 additions & 0 deletions lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@ namespace llvm {
class RISCVTargetStreamer : public MCTargetStreamer {
public:
RISCVTargetStreamer(MCStreamer &S);

virtual void emitDirectiveOptionRVC() = 0;
virtual void emitDirectiveOptionNoRVC() = 0;
};

// This part is for ascii assembly output
class RISCVTargetAsmStreamer : public RISCVTargetStreamer {
formatted_raw_ostream &OS;

public:
RISCVTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);

void emitDirectiveOptionRVC() override;
void emitDirectiveOptionNoRVC() override;
};

}
#endif
15 changes: 15 additions & 0 deletions test/CodeGen/RISCV/option-norvc.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
; RUN: llc -mtriple=riscv32 -mattr=+c -filetype=obj < %s\
; RUN: | llvm-objdump -triple=riscv32 -mattr=+c -d -riscv-no-aliases -\
; RUN: | FileCheck -check-prefix=CHECK %s

; This test demonstrates that .option norvc has no effect on codegen when
; emitting an ELF directly.

define i32 @add(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: add:
; CHECK: c.add a0, a1
; CHECK-NEXT: c.jr ra
tail call void asm sideeffect ".option norvc", ""()
%add = add nsw i32 %b, %a
ret i32 %add
}
15 changes: 15 additions & 0 deletions test/CodeGen/RISCV/option-rvc.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
; RUN: llc -mtriple=riscv32 -filetype=obj < %s\
; RUN: | llvm-objdump -triple=riscv32 -mattr=+c -d -riscv-no-aliases -\
; RUN: | FileCheck -check-prefix=CHECK %s

; This test demonstrates that .option norvc has no effect on codegen when
; emitting an ELF directly.

define i32 @add(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: add:
; CHECK: add a0, a1, a0
; CHECK-NEXT: jalr zero, ra, 0
tail call void asm sideeffect ".option rvc", ""()
%add = add nsw i32 %b, %a
ret i32 %add
}
17 changes: 17 additions & 0 deletions test/MC/RISCV/option-invalid.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# RUN: not llvm-mc -triple riscv32 < %s 2>&1 \
# RUN: | FileCheck -check-prefixes=CHECK %s

# CHECK: error: unexpected token, expected identifier
.option

# CHECK: error: unexpected token, expected identifier
.option 123

# CHECK: error: unexpected token, expected identifier
.option "str"

# CHECK: error: unexpected token, expected end of statement
.option rvc foo

# CHECK: warning: unknown option, expected 'rvc' or 'norvc'
.option bar
90 changes: 90 additions & 0 deletions test/MC/RISCV/option-rvc.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# RUN: llvm-mc -triple riscv32 -show-encoding < %s \
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s
# RUN: llvm-mc -triple riscv32 -show-encoding \
# RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK,CHECK-INST %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 riscv32 -filetype=obj < %s \
# RUN: | llvm-objdump -triple riscv32 -mattr=+c -d -riscv-no-aliases - \
# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s

# RUN: llvm-mc -triple riscv64 -show-encoding < %s \
# RUN: | FileCheck -check-prefixes=CHECK-ALIAS %s
# RUN: llvm-mc -triple riscv64 -show-encoding \
# RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK-INST %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
# RUN: llvm-mc -triple riscv64 -filetype=obj < %s \
# RUN: | llvm-objdump -triple riscv64 -mattr=+c -d -riscv-no-aliases - \
# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s

# CHECK-BYTES: 13 85 05 00
# CHECK-ALIAS: mv a0, a1
# CHECK-INST: addi a0, a1, 0
# CHECK: # encoding: [0x13,0x85,0x05,0x00]
addi a0, a1, 0

# CHECK-BYTES: 13 04 c1 3f
# CHECK-ALIAS: addi s0, sp, 1020
# CHECK-INST: addi s0, sp, 1020
# CHECK: # encoding: [0x13,0x04,0xc1,0x3f]
addi s0, sp, 1020


# CHECK: .option rvc
.option rvc
# CHECK-BYTES: 2e 85
# CHECK-ALIAS: add a0, zero, a1
# CHECK-INST: c.mv a0, a1
# CHECK: # encoding: [0x2e,0x85]
addi a0, a1, 0

# CHECK-BYTES: e0 1f
# CHECK-ALIAS: addi s0, sp, 1020
# CHECK-INST: c.addi4spn s0, sp, 1020
# CHECK: # encoding: [0xe0,0x1f]
addi s0, sp, 1020

# CHECK: .option norvc
.option norvc
# CHECK-BYTES: 13 85 05 00
# CHECK-ALIAS: mv a0, a1
# CHECK-INST: addi a0, a1, 0
# CHECK: # encoding: [0x13,0x85,0x05,0x00]
addi a0, a1, 0

# CHECK-BYTES: 13 04 c1 3f
# CHECK-ALIAS: addi s0, sp, 1020
# CHECK-INST: addi s0, sp, 1020
# CHECK: # encoding: [0x13,0x04,0xc1,0x3f]
addi s0, sp, 1020

# CHECK: .option rvc
.option rvc
# CHECK-BYTES: 2e 85
# CHECK-ALIAS: add a0, zero, a1
# CHECK-INST: c.mv a0, a1
# CHECK: # encoding: [0x2e,0x85]
addi a0, a1, 0

# CHECK-BYTES: e0 1f
# CHECK-ALIAS: addi s0, sp, 1020
# CHECK-INST: c.addi4spn s0, sp, 1020
# CHECK: # encoding: [0xe0,0x1f]
addi s0, sp, 1020

# CHECK: .option norvc
.option norvc
# CHECK-BYTES: 13 85 05 00
# CHECK-ALIAS: mv a0, a1
# CHECK-INST: addi a0, a1, 0
# CHECK: # encoding: [0x13,0x85,0x05,0x00]
addi a0, a1, 0

# CHECK-BYTES: 13 04 c1 3f
# CHECK-ALIAS: addi s0, sp, 1020
# CHECK-INST: addi s0, sp, 1020
# CHECK: # encoding: [0x13,0x04,0xc1,0x3f]
addi s0, sp, 1020

0 comments on commit 0d10241

Please sign in to comment.