#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"
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;
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,
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());
MCELFStreamer &RISCVTargetELFStreamer::getStreamer() {
return static_cast<MCELFStreamer &>(Streamer);
}
+
+void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {}
+void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {}
public:
MCELFStreamer &getStreamer();
RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
+
+ virtual void emitDirectiveOptionRVC();
+ virtual void emitDirectiveOptionNoRVC();
};
}
#endif
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() {
TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo);
TargetRegistry::RegisterObjectTargetStreamer(
*T, createRISCVObjectTargetStreamer);
+
+ // Register the asm target streamer.
+ TargetRegistry::RegisterAsmTargetStreamer(*T, createRISCVAsmTargetStreamer);
}
}
//===----------------------------------------------------------------------===//
#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";
+}
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
--- /dev/null
+; 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
+}
--- /dev/null
+; 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
+}
--- /dev/null
+# 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
--- /dev/null
+# 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