Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -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" @@ -37,6 +38,11 @@ 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(TS); + } + unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; @@ -67,6 +73,23 @@ 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, @@ -984,7 +1007,60 @@ 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 X(getTheRISCV32Target()); Index: lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -19,6 +19,9 @@ public: MCELFStreamer &getStreamer(); RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI); + + virtual void emitDirectiveOptionRVC(); + virtual void emitDirectiveOptionNoRVC(); }; } #endif Index: lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -37,3 +37,6 @@ MCELFStreamer &RISCVTargetELFStreamer::getStreamer() { return static_cast(Streamer); } + +void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {} +void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {} Index: lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp @@ -74,7 +74,14 @@ 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() { @@ -88,5 +95,8 @@ TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo); TargetRegistry::RegisterObjectTargetStreamer( *T, createRISCVObjectTargetStreamer); + + // Register the asm target streamer. + TargetRegistry::RegisterAsmTargetStreamer(*T, createRISCVAsmTargetStreamer); } } Index: lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h +++ lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h @@ -17,6 +17,21 @@ 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 Index: lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp @@ -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"; +} Index: test/MC/RISCV/option-invalid.s =================================================================== --- /dev/null +++ test/MC/RISCV/option-invalid.s @@ -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 Index: test/MC/RISCV/option-rvc.s =================================================================== --- /dev/null +++ test/MC/RISCV/option-rvc.s @@ -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