summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/MC/MCInst.h2
-rw-r--r--llvm/lib/MC/MCInst.cpp18
-rw-r--r--llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp12
-rw-r--r--llvm/lib/Target/RISCV/CMakeLists.txt1
-rw-r--r--llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp16
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp1
-rw-r--r--llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h1
-rw-r--r--llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp11
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfo.td32
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfoC.td263
-rw-r--r--llvm/test/CodeGen/RISCV/alu32.ll42
-rw-r--r--llvm/test/CodeGen/RISCV/branch.ll32
-rw-r--r--llvm/test/CodeGen/RISCV/compress-Pseudo.ll10
-rw-r--r--llvm/test/CodeGen/RISCV/compress-inline-asm.ll15
-rw-r--r--llvm/test/MC/RISCV/cnop.s2
-rw-r--r--llvm/test/MC/RISCV/compress-cjal.s17
-rw-r--r--llvm/test/MC/RISCV/compress-rv32d.s44
-rw-r--r--llvm/test/MC/RISCV/compress-rv32f.s32
-rw-r--r--llvm/test/MC/RISCV/compress-rv32i.s207
-rw-r--r--llvm/test/MC/RISCV/compress-rv64i.s60
-rw-r--r--llvm/test/MC/RISCV/compressed-relocations.s20
-rw-r--r--llvm/test/MC/RISCV/fixups-compressed.s2
-rw-r--r--llvm/test/MC/RISCV/relocations.s14
-rw-r--r--llvm/test/MC/RISCV/rv32-relaxation.s26
-rw-r--r--llvm/test/MC/RISCV/rv64-relaxation.s22
-rw-r--r--llvm/utils/TableGen/CMakeLists.txt1
-rw-r--r--llvm/utils/TableGen/RISCVCompressInstEmitter.cpp806
-rw-r--r--llvm/utils/TableGen/TableGen.cpp6
-rw-r--r--llvm/utils/TableGen/TableGenBackends.h1
29 files changed, 1672 insertions, 44 deletions
diff --git a/llvm/include/llvm/MC/MCInst.h b/llvm/include/llvm/MC/MCInst.h
index db28fd0fd6d..b472e61a34f 100644
--- a/llvm/include/llvm/MC/MCInst.h
+++ b/llvm/include/llvm/MC/MCInst.h
@@ -150,6 +150,8 @@ public:
void print(raw_ostream &OS) const;
void dump() const;
+ bool isBareSymbolRef() const;
+ bool evaluateAsConstantImm(int64_t &Imm) const;
};
template <> struct isPodLike<MCOperand> { static const bool value = true; };
diff --git a/llvm/lib/MC/MCInst.cpp b/llvm/lib/MC/MCInst.cpp
index f6d1d3cffca..5f026dc6b26 100644
--- a/llvm/lib/MC/MCInst.cpp
+++ b/llvm/lib/MC/MCInst.cpp
@@ -10,6 +10,7 @@
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -35,6 +36,23 @@ void MCOperand::print(raw_ostream &OS) const {
OS << ">";
}
+bool MCOperand::evaluateAsConstantImm(int64_t &Imm) const {
+ if (isImm()) {
+ Imm = getImm();
+ return true;
+ }
+ return false;
+}
+
+bool MCOperand::isBareSymbolRef() const {
+ assert(isExpr() &&
+ "isBareSymbolRef expects only expressions");
+ const MCExpr *Expr = getExpr();
+ MCExpr::ExprKind Kind = getExpr()->getKind();
+ return Kind == MCExpr::SymbolRef &&
+ cast<MCSymbolRefExpr>(Expr)->getKind() == MCSymbolRefExpr::VK_None;
+}
+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void MCOperand::dump() const {
print(dbgs());
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 035c1ef6ac7..59654f9b601 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -26,6 +26,10 @@
using namespace llvm;
+// Include the auto-generated portion of the compress emitter.
+#define GEN_COMPRESS_INSTR
+#include "RISCVGenCompressInstEmitter.inc"
+
namespace {
struct RISCVOperand;
@@ -595,10 +599,14 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
default:
break;
- case Match_Success:
+ case Match_Success: {
+ MCInst CInst;
+ bool Res = compressInst(CInst, Inst, getSTI(), Out.getContext());
+ CInst.setLoc(IDLoc);
Inst.setLoc(IDLoc);
- Out.EmitInstruction(Inst, getSTI());
+ Out.EmitInstruction((Res ? CInst : Inst), getSTI());
return false;
+ }
case Match_MissingFeature:
return Error(IDLoc, "instruction use requires an option to be enabled");
case Match_MnemonicFail:
diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index fa9adeb25eb..cb18467d478 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -2,6 +2,7 @@ set(LLVM_TARGET_DEFINITIONS RISCV.td)
tablegen(LLVM RISCVGenAsmMatcher.inc -gen-asm-matcher)
tablegen(LLVM RISCVGenAsmWriter.inc -gen-asm-writer)
+tablegen(LLVM RISCVGenCompressInstEmitter.inc -gen-compress-inst-emitter)
tablegen(LLVM RISCVGenDAGISel.inc -gen-dag-isel)
tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info)
diff --git a/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp b/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
index f1fa2ecbcb2..300e6fd9750 100644
--- a/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
+++ b/llvm/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
@@ -13,6 +13,7 @@
#include "RISCVInstPrinter.h"
#include "MCTargetDesc/RISCVBaseInfo.h"
+#include "MCTargetDesc/RISCVMCExpr.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
@@ -30,6 +31,10 @@ using namespace llvm;
#define PRINT_ALIAS_INSTR
#include "RISCVGenAsmWriter.inc"
+// Include the auto-generated portion of the compress emitter.
+#define GEN_UNCOMPRESS_INSTR
+#include "RISCVGenCompressInstEmitter.inc"
+
static cl::opt<bool>
NoAliases("riscv-no-aliases",
cl::desc("Disable the emission of assembler pseudo instructions"),
@@ -38,8 +43,15 @@ NoAliases("riscv-no-aliases",
void RISCVInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
StringRef Annot, const MCSubtargetInfo &STI) {
- if (NoAliases || !printAliasInstr(MI, STI, O))
- printInstruction(MI, STI, O);
+ bool Res = false;
+ const MCInst *NewMI = MI;
+ MCInst UncompressedMI;
+ if (!NoAliases)
+ Res = uncompressInst(UncompressedMI, *MI, MRI, STI);
+ if (Res)
+ NewMI = const_cast<MCInst*>(&UncompressedMI);
+ if (NoAliases || !printAliasInstr(NewMI, STI, O))
+ printInstruction(NewMI, STI, O);
printAnnotation(O, Annot);
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
index 68cdb3783b1..4d1573ab8ef 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "RISCV.h"
#include "RISCVMCExpr.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
index c49593f0b9c..e428b0d30d3 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
@@ -20,6 +20,7 @@
namespace llvm {
class StringRef;
+class MCOperand;
class RISCVMCExpr : public MCTargetExpr {
public:
enum VariantKind {
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index bbaa8ec454f..bdf8e5d840b 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -14,6 +14,7 @@
#include "RISCV.h"
#include "InstPrinter/RISCVInstPrinter.h"
+#include "MCTargetDesc/RISCVMCExpr.h"
#include "RISCVTargetMachine.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineConstantPool.h"
@@ -48,6 +49,7 @@ public:
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &OS) override;
+ void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
const MachineInstr *MI);
@@ -58,6 +60,15 @@ public:
};
}
+#define GEN_COMPRESS_INSTR
+#include "RISCVGenCompressInstEmitter.inc"
+void RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
+ MCInst CInst;
+ bool Res = compressInst(CInst, Inst, *TM.getMCSubtargetInfo(),
+ OutStreamer->getContext());
+ AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
+}
+
// Simple pseudo-instructions have their lowering (with expansion to real
// instructions) auto-generated.
#include "RISCVGenMCPseudoLowering.inc"
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 8b5b89ba422..1c429da7419 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -83,6 +83,14 @@ def uimmlog2xlen : Operand<XLenVT>, ImmLeaf<XLenVT, [{
let ParserMatchClass = UImmLog2XLenAsmOperand;
// TODO: should ensure invalid shamt is rejected when decoding.
let DecoderMethod = "decodeUImmOperand<6>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (!MCOp.evaluateAsConstantImm(Imm))
+ return false;
+ if (STI.getTargetTriple().isArch64Bit())
+ return isUInt<6>(Imm);
+ return isUInt<5>(Imm);
+ }];
}
def uimm5 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isUInt<5>(Imm);}]> {
@@ -94,6 +102,12 @@ def simm12 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isInt<12>(Imm);}]> {
let ParserMatchClass = SImmAsmOperand<12>;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeSImmOperand<12>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (MCOp.evaluateAsConstantImm(Imm))
+ return isInt<12>(Imm);
+ return MCOp.isBareSymbolRef();
+ }];
}
def uimm12 : Operand<XLenVT> {
@@ -106,12 +120,24 @@ def simm13_lsb0 : Operand<OtherVT> {
let ParserMatchClass = SImmAsmOperand<13, "Lsb0">;
let EncoderMethod = "getImmOpValueAsr1";
let DecoderMethod = "decodeSImmOperandAndLsl1<13>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (MCOp.evaluateAsConstantImm(Imm))
+ return isShiftedInt<12, 1>(Imm);
+ return MCOp.isBareSymbolRef();
+ }];
}
def uimm20 : Operand<XLenVT> {
let ParserMatchClass = UImmAsmOperand<20>;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeUImmOperand<20>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (MCOp.evaluateAsConstantImm(Imm))
+ return isUInt<20>(Imm);
+ return MCOp.isBareSymbolRef();
+ }];
}
// A 21-bit signed immediate where the least significant bit is zero.
@@ -119,6 +145,12 @@ def simm21_lsb0 : Operand<OtherVT> {
let ParserMatchClass = SImmAsmOperand<21, "Lsb0">;
let EncoderMethod = "getImmOpValueAsr1";
let DecoderMethod = "decodeSImmOperandAndLsl1<21>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (MCOp.evaluateAsConstantImm(Imm))
+ return isShiftedInt<20, 1>(Imm);
+ return MCOp.isBareSymbolRef();
+ }];
}
// A parameterized register class alternative to i32imm/i64imm from Target.td.
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
index b3566878e97..c1cbfdcb5cf 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
@@ -27,12 +27,26 @@ def uimmlog2xlennonzero : Operand<XLenVT>, ImmLeaf<XLenVT, [{
let ParserMatchClass = UImmLog2XLenNonZeroAsmOperand;
// TODO: should ensure invalid shamt is rejected when decoding.
let DecoderMethod = "decodeUImmOperand<6>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (!MCOp.evaluateAsConstantImm(Imm))
+ return false;
+ if (STI.getTargetTriple().isArch64Bit())
+ return isUInt<6>(Imm) && (Imm != 0);
+ return isUInt<5>(Imm) && (Imm != 0);
+ }];
}
def simm6 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isInt<6>(Imm);}]> {
let ParserMatchClass = SImmAsmOperand<6>;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeSImmOperand<6>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (MCOp.evaluateAsConstantImm(Imm))
+ return isInt<6>(Imm);
+ return MCOp.isBareSymbolRef();
+ }];
}
def simm6nonzero : Operand<XLenVT>,
@@ -40,6 +54,12 @@ def simm6nonzero : Operand<XLenVT>,
let ParserMatchClass = SImmAsmOperand<6, "NonZero">;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeSImmOperand<6>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (MCOp.evaluateAsConstantImm(Imm))
+ return (Imm != 0) && isInt<6>(Imm);
+ return MCOp.isBareSymbolRef();
+ }];
}
def CLUIImmAsmOperand : AsmOperandClass {
@@ -61,6 +81,13 @@ def c_lui_imm : Operand<XLenVT>,
let ParserMatchClass = CLUIImmAsmOperand;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeCLUIImmOperand";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (MCOp.evaluateAsConstantImm(Imm))
+ return (Imm != 0) && (isUInt<5>(Imm) ||
+ (Imm >= 0xfffe0 && Imm <= 0xfffff));
+ return MCOp.isBareSymbolRef();
+ }];
}
// A 7-bit unsigned immediate where the least significant two bits are zero.
@@ -69,6 +96,12 @@ def uimm7_lsb00 : Operand<XLenVT>,
let ParserMatchClass = UImmAsmOperand<7, "Lsb00">;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeUImmOperand<7>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (!MCOp.evaluateAsConstantImm(Imm))
+ return false;
+ return isShiftedUInt<5, 2>(Imm);
+ }];
}
// A 8-bit unsigned immediate where the least significant two bits are zero.
@@ -77,6 +110,12 @@ def uimm8_lsb00 : Operand<XLenVT>,
let ParserMatchClass = UImmAsmOperand<8, "Lsb00">;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeUImmOperand<8>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (!MCOp.evaluateAsConstantImm(Imm))
+ return false;
+ return isShiftedUInt<6, 2>(Imm);
+ }];
}
// A 8-bit unsigned immediate where the least significant three bits are zero.
@@ -85,6 +124,12 @@ def uimm8_lsb000 : Operand<XLenVT>,
let ParserMatchClass = UImmAsmOperand<8, "Lsb000">;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeUImmOperand<8>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (!MCOp.evaluateAsConstantImm(Imm))
+ return false;
+ return isShiftedUInt<5, 3>(Imm);
+ }];
}
// A 9-bit signed immediate where the least significant bit is zero.
@@ -92,6 +137,13 @@ def simm9_lsb0 : Operand<OtherVT> {
let ParserMatchClass = SImmAsmOperand<9, "Lsb0">;
let EncoderMethod = "getImmOpValueAsr1";
let DecoderMethod = "decodeSImmOperandAndLsl1<9>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (MCOp.evaluateAsConstantImm(Imm))
+ return isShiftedInt<8, 1>(Imm);
+ return MCOp.isBareSymbolRef();
+
+ }];
}
// A 9-bit unsigned immediate where the least significant three bits are zero.
@@ -100,6 +152,12 @@ def uimm9_lsb000 : Operand<XLenVT>,
let ParserMatchClass = UImmAsmOperand<9, "Lsb000">;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeUImmOperand<9>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (!MCOp.evaluateAsConstantImm(Imm))
+ return false;
+ return isShiftedUInt<6, 3>(Imm);
+ }];
}
// A 10-bit unsigned immediate where the least significant two bits are zero
@@ -110,6 +168,12 @@ def uimm10_lsb00nonzero : Operand<XLenVT>,
let ParserMatchClass = UImmAsmOperand<10, "Lsb00NonZero">;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeUImmOperand<10>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (!MCOp.evaluateAsConstantImm(Imm))
+ return false;
+ return isShiftedUInt<8, 2>(Imm) && (Imm != 0);
+ }];
}
// A 10-bit signed immediate where the least significant four bits are zero.
@@ -119,13 +183,25 @@ def simm10_lsb0000nonzero : Operand<XLenVT>,
let ParserMatchClass = SImmAsmOperand<10, "Lsb0000NonZero">;
let EncoderMethod = "getImmOpValue";
let DecoderMethod = "decodeSImmOperand<10>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (!MCOp.evaluateAsConstantImm(Imm))
+ return false;
+ return isShiftedInt<6, 4>(Imm);
+ }];
}
// A 12-bit signed immediate where the least significant bit is zero.
-def simm12_lsb0 : Operand<OtherVT> {
+def simm12_lsb0 : Operand<XLenVT> {
let ParserMatchClass = SImmAsmOperand<12, "Lsb0">;
let EncoderMethod = "getImmOpValueAsr1";
let DecoderMethod = "decodeSImmOperandAndLsl1<12>";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (MCOp.evaluateAsConstantImm(Imm))
+ return isShiftedInt<11, 1>(Imm);
+ return MCOp.isBareSymbolRef();
+ }];
}
//===----------------------------------------------------------------------===//
@@ -442,3 +518,188 @@ def C_SDSP : CStackStore<0b111, "c.sdsp", GPR, uimm9_lsb000> {
}
} // Predicates = [HasStdExtC]
+
+//===----------------------------------------------------------------------===//
+// Compress Instruction tablegen backend.
+//===----------------------------------------------------------------------===//
+
+class CompressPat<dag input, dag output> {
+ dag Input = input;
+ dag Output = output;
+ list<Predicate> Predicates = [];
+}
+
+// Patterns are defined in the same order the compressed instructions appear
+// on page 82 of the ISA manual.
+
+// Quadrant 0
+let Predicates = [HasStdExtC] in {
+def : CompressPat<(ADDI GPRC:$rd, SP:$rs1, uimm10_lsb00nonzero:$imm),
+ (C_ADDI4SPN GPRC:$rd, SP:$rs1, uimm10_lsb00nonzero:$imm)>;
+} // Predicates = [HasStdExtC]
+
+let Predicates = [HasStdExtC, HasStdExtD] in {
+def : CompressPat<(FLD FPR64C:$rd, GPRC:$rs1, uimm8_lsb000:$imm),
+ (C_FLD FPR64C:$rd, GPRC:$rs1, uimm8_lsb000:$imm)>;
+} // Predicates = [HasStdExtC, HasStdExtD]
+
+let Predicates = [HasStdExtC] in {
+def : CompressPat<(LW GPRC:$rd, GPRC:$rs1, uimm7_lsb00:$imm),
+ (C_LW GPRC:$rd, GPRC:$rs1, uimm7_lsb00:$imm)>;
+} // Predicates = [HasStdExtC]
+
+let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in {
+def : CompressPat<(FLW FPR32C:$rd, GPRC:$rs1, uimm7_lsb00:$imm),
+ (C_FLW FPR32C:$rd, GPRC:$rs1, uimm7_lsb00:$imm)>;
+} // Predicates = [HasStdExtC, HasStdExtF, IsRV32]
+
+let Predicates = [HasStdExtC, IsRV64] in {
+def : CompressPat<(LD GPRC:$rd, GPRC:$rs1, uimm8_lsb000:$imm),
+ (C_LD GPRC:$rd, GPRC:$rs1, uimm8_lsb000:$imm)>;
+} // Predicates = [HasStdExtC, IsRV64]
+
+let Predicates = [HasStdExtC, HasStdExtD] in {
+def : CompressPat<(FSD FPR64C:$rs2, GPRC:$rs1, uimm8_lsb000:$imm),
+ (C_FSD FPR64C:$rs2, GPRC:$rs1, uimm8_lsb000:$imm)>;
+} // Predicates = [HasStdExtC, HasStdExtD]
+
+let Predicates = [HasStdExtC] in {
+def : CompressPat<(SW GPRC:$rs2, GPRC:$rs1, uimm7_lsb00:$imm),
+ (C_SW GPRC:$rs2, GPRC:$rs1, uimm7_lsb00:$imm)>;
+} // Predicates = [HasStdExtC]
+
+let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in {
+def : CompressPat<(FSW FPR32C:$rs2, GPRC:$rs1,uimm7_lsb00:$imm),
+ (C_FSW FPR32C:$rs2, GPRC:$rs1, uimm7_lsb00:$imm)>;
+} // Predicate = [HasStdExtC, HasStdExtF, IsRV32]
+
+let Predicates = [HasStdExtC, IsRV64] in {
+def : CompressPat<(SD GPRC:$rs2, GPRC:$rs1, uimm8_lsb000:$imm),
+ (C_SD GPRC:$rs2, GPRC:$rs1, uimm8_lsb000:$imm)>;
+} // Predicates = [HasStdExtC, IsRV64]
+
+// Quadrant 1
+let Predicates = [HasStdExtC] in {
+def : CompressPat<(ADDI X0, X0, 0), (C_NOP)>;
+def : CompressPat<(ADDI GPRNoX0:$rs1, GPRNoX0:$rs1, simm6nonzero:$imm),
+ (C_ADDI GPRNoX0:$rs1, simm6nonzero:$imm)>;
+} // Predicates = [HasStdExtC]
+
+let Predicates = [HasStdExtC, IsRV32] in {
+def : CompressPat<(JAL X1, simm12_lsb0:$offset),
+ (C_JAL simm12_lsb0:$offset)>;
+} // Predicates = [HasStdExtC, IsRV32]
+
+let Predicates = [HasStdExtC, IsRV64] in {
+def : CompressPat<(ADDIW GPRNoX0:$rs1, GPRNoX0:$rs1, simm6:$imm),
+ (C_ADDIW GPRNoX0:$rs1, simm6:$imm)>;
+} // Predicates = [HasStdExtC, IsRV64]
+
+let Predicates = [HasStdExtC] in {
+def : CompressPat<(ADDI GPRNoX0:$rd, X0, simm6:$imm),
+ (C_LI GPRNoX0:$rd, simm6:$imm)>;
+def : CompressPat<(ADDI X2, X2, simm10_lsb0000nonzero:$imm),
+ (C_ADDI16SP X2, simm10_lsb0000nonzero:$imm)>;
+def : CompressPat<(LUI GPRNoX0X2:$rd, c_lui_imm:$imm),
+ (C_LUI GPRNoX0X2:$rd, c_lui_imm:$imm)>;
+def : CompressPat<(SRLI GPRC:$rs1, GPRC:$rs1, uimmlog2xlennonzero:$imm),
+ (C_SRLI GPRC:$rs1, uimmlog2xlennonzero:$imm)>;
+def : CompressPat<(SRAI GPRC:$rs1, GPRC:$rs1, uimmlog2xlennonzero:$imm),
+ (C_SRAI GPRC:$rs1, uimmlog2xlennonzero:$imm)>;
+def : CompressPat<(ANDI GPRC:$rs1, GPRC:$rs1, simm6:$imm),
+ (C_ANDI GPRC:$rs1, simm6:$imm)>;
+def : CompressPat<(SUB GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
+ (C_SUB GPRC:$rs1, GPRC:$rs2)>;
+def : CompressPat<(XOR GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
+ (C_XOR GPRC:$rs1, GPRC:$rs2)>;
+def : CompressPat<(XOR GPRC:$rs1, GPRC:$rs2, GPRC:$rs1),
+ (C_XOR GPRC:$rs1, GPRC:$rs2)>;
+def : CompressPat<(OR GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
+ (C_OR GPRC:$rs1, GPRC:$rs2)>;
+def : CompressPat<(OR GPRC:$rs1, GPRC:$rs2, GPRC:$rs1),
+ (C_OR GPRC:$rs1, GPRC:$rs2)>;
+def : CompressPat<(AND GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
+ (C_AND GPRC:$rs1, GPRC:$rs2)>;
+def : CompressPat<(AND GPRC:$rs1, GPRC:$rs2, GPRC:$rs1),
+ (C_AND GPRC:$rs1, GPRC:$rs2)>;
+} // Predicates = [HasStdExtC]
+
+let Predicates = [HasStdExtC, IsRV64] in {
+def : CompressPat<(SUBW GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
+ (C_SUBW GPRC:$rs1, GPRC:$rs2)>;
+def : CompressPat<(ADDW GPRC:$rs1, GPRC:$rs1, GPRC:$rs2),
+ (C_ADDW GPRC:$rs1, GPRC:$rs2)>;
+def : CompressPat<(ADDW GPRC:$rs1, GPRC:$rs2, GPRC:$rs1),
+ (C_ADDW GPRC:$rs1, GPRC:$rs2)>;
+} // Predicates = [HasStdExtC, IsRV64]
+
+let Predicates = [HasStdExtC] in {
+def : CompressPat<(JAL X0, simm12_lsb0:$offset),
+ (C_J simm12_lsb0:$offset)>;
+def : CompressPat<(BEQ GPRC:$rs1, X0, simm9_lsb0:$imm),
+ (C_BEQZ GPRC:$rs1, simm9_lsb0:$imm)>;
+def : CompressPat<(BNE GPRC:$rs1, X0, simm9_lsb0:$imm),
+ (C_BNEZ GPRC:$rs1, simm9_lsb0:$imm)>;
+} // Predicates = [HasStdExtC]
+
+// Quadrant 2
+let Predicates = [HasStdExtC] in {
+def : CompressPat<(SLLI GPRNoX0:$rs1, GPRNoX0:$rs1, uimmlog2xlennonzero:$imm),
+ (C_SLLI GPRNoX0:$rs1, uimmlog2xlennonzero:$imm)>;
+} // Predicates = [HasStdExtC]
+
+let Predicates = [HasStdExtC, HasStdExtD] in {
+def : CompressPat<(FLD FPR64:$rd, SP:$rs1, uimm9_lsb000:$imm),
+ (C_FLDSP FPR64:$rd, SP:$rs1, uimm9_lsb000:$imm)>;
+} // Predicates = [HasStdExtC, HasStdExtD]
+
+let Predicates = [HasStdExtC] in {
+def : CompressPat<(LW GPRNoX0:$rd, SP:$rs1, uimm8_lsb00:$imm),
+ (C_LWSP GPRNoX0:$rd, SP:$rs1, uimm8_lsb00:$imm)>;
+} // Predicates = [HasStdExtC]
+
+let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in {
+def : CompressPat<(FLW FPR32:$rd, SP:$rs1, uimm8_lsb00:$imm),
+ (C_FLWSP FPR32:$rd, SP:$rs1, uimm8_lsb00:$imm)>;
+} // Predicates = [HasStdExtC, HasStdExtF, IsRV32]
+
+let Predicates = [HasStdExtC, IsRV64] in {
+def : CompressPat<(LD GPRNoX0:$rd, SP:$rs1, uimm9_lsb000:$imm),
+ (C_LDSP GPRNoX0:$rd, SP:$rs1, uimm9_lsb000:$imm)>;
+} // Predicates = [HasStdExtC, IsRV64]
+
+let Predicates = [HasStdExtC] in {
+def : CompressPat<(JALR X0, GPRNoX0:$rs1, 0),
+ (C_JR GPRNoX0:$rs1)>;
+def : CompressPat<(ADD GPRNoX0:$rs1, X0, GPRNoX0:$rs2),
+ (C_MV GPRNoX0:$rs1, GPRNoX0:$rs2)>;
+def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs2, X0),
+ (C_MV GPRNoX0:$rs1, GPRNoX0:$rs2)>;
+def : CompressPat<(EBREAK), (C_EBREAK)>;
+def : CompressPat<(JALR X1, GPRNoX0:$rs1, 0),
+ (C_JALR GPRNoX0:$rs1)>;
+def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs1, GPRNoX0:$rs2),
+ (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>;
+def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs2, GPRNoX0:$rs1),
+ (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>;
+} // Predicates = [HasStdExtC]
+
+let Predicates = [HasStdExtC, HasStdExtD] in {
+def : CompressPat<(FSD FPR64:$rs2, SP:$rs1, uimm9_lsb000:$imm),
+ (C_FSDSP FPR64:$rs2, SP:$rs1, uimm9_lsb000:$imm)>;
+} // Predicates = [HasStdExtC, HasStdExtD]
+
+let Predicates = [HasStdExtC] in {
+def : CompressPat<(SW GPR:$rs2, SP:$rs1, uimm8_lsb00:$imm),
+ (C_SWSP GPR:$rs2, SP:$rs1, uimm8_lsb00:$imm)>;
+} // Predicates = [HasStdExtC]
+
+let Predicates = [HasStdExtC, HasStdExtF, IsRV32] in {
+def : CompressPat<(FSW FPR32:$rs2, SP:$rs1, uimm8_lsb00:$imm),
+ (C_FSWSP FPR32:$rs2, SP:$rs1, uimm8_lsb00:$imm)>;
+} // Predicates = [HasStdExtC, HasStdExtF, IsRV32]
+
+let Predicates = [HasStdExtC, IsRV64] in {
+def : CompressPat<(SD GPR:$rs2, SP:$rs1, uimm9_lsb000:$imm),
+ (C_SDSP GPR:$rs2, SP:$rs1, uimm9_lsb000:$imm)>;
+} // Predicates = [HasStdExtC, IsRV64]
diff --git a/llvm/test/CodeGen/RISCV/alu32.ll b/llvm/test/CodeGen/RISCV/alu32.ll
index 6ecd08878dd..f34efe932b8 100644
--- a/llvm/test/CodeGen/RISCV/alu32.ll
+++ b/llvm/test/CodeGen/RISCV/alu32.ll
@@ -2,6 +2,10 @@
; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
; RUN: | FileCheck %s -check-prefix=RV32I
+; RUN: llc -mtriple=riscv32 -mattr=+c -filetype=obj < %s \
+; RUN: |llvm-objdump -d -triple=riscv32 -mattr=+c -riscv-no-aliases - \
+; RUN: | FileCheck -check-prefix=RV32IC %s
+
; These tests are each targeted at a particular RISC-V ALU instruction. Other
; files in this folder exercise LLVM IR instructions that don't directly match a
; RISC-V instruction
@@ -13,6 +17,10 @@ define i32 @addi(i32 %a) nounwind {
; RV32I: # %bb.0:
; RV32I-NEXT: addi a0, a0, 1
; RV32I-NEXT: ret
+
+; RV32IC-LABEL: addi:
+; RV32IC-NEXT: c.addi a0, 1
+; RV32IC-NEXT: c.jr ra
%1 = add i32 %a, 1
ret i32 %1
}
@@ -60,6 +68,11 @@ define i32 @andi(i32 %a) nounwind {
; RV32I: # %bb.0:
; RV32I-NEXT: andi a0, a0, 6
; RV32I-NEXT: ret
+
+
+; RV32IC-LABEL: andi:
+; RV32IC: c.andi a0, 6
+; RV32IC: c.jr ra
%1 = and i32 %a, 6
ret i32 %1
}
@@ -69,6 +82,10 @@ define i32 @slli(i32 %a) nounwind {
; RV32I: # %bb.0:
; RV32I-NEXT: slli a0, a0, 7
; RV32I-NEXT: ret
+
+; RV32IC-LABEL: slli:
+; RV32IC-NEXT: slli a0, 7
+; RV32IC-NEXT: c.jr ra
%1 = shl i32 %a, 7
ret i32 %1
}
@@ -78,6 +95,10 @@ define i32 @srli(i32 %a) nounwind {
; RV32I: # %bb.0:
; RV32I-NEXT: srli a0, a0, 8
; RV32I-NEXT: ret
+
+; RV32IC-LABEL: srli:
+; RV32IC-NEXT: c.srli a0, 8
+; RV32IC-NEXT: c.jr ra
%1 = lshr i32 %a, 8
ret i32 %1
}
@@ -87,6 +108,10 @@ define i32 @srai(i32 %a) nounwind {
; RV32I: # %bb.0:
; RV32I-NEXT: srai a0, a0, 9
; RV32I-NEXT: ret
+
+; RV32IC-LABEL: srai:
+; RV32IC-NEXT: c.srai a0, 9
+; RV32IC-NEXT: c.jr ra
%1 = ashr i32 %a, 9
ret i32 %1
}
@@ -98,6 +123,11 @@ define i32 @add(i32 %a, i32 %b) nounwind {
; RV32I: # %bb.0:
; RV32I-NEXT: add a0, a0, a1
; RV32I-NEXT: ret
+
+; RV32IC-LABEL: add:
+; RV32IC-NEXT: c.add a0, a1
+; RV32IC-NEXT: c.jr ra
+
%1 = add i32 %a, %b
ret i32 %1
}
@@ -107,6 +137,10 @@ define i32 @sub(i32 %a, i32 %b) nounwind {
; RV32I: # %bb.0:
; RV32I-NEXT: sub a0, a0, a1
; RV32I-NEXT: ret
+
+; RV32IC-LABEL: sub:
+; RV32IC-NEXT: c.sub a0, a1
+; RV32IC-NEXT: c.jr ra
%1 = sub i32 %a, %b
ret i32 %1
}
@@ -145,6 +179,10 @@ define i32 @xor(i32 %a, i32 %b) nounwind {
; RV32I: # %bb.0:
; RV32I-NEXT: xor a0, a0, a1
; RV32I-NEXT: ret
+
+; RV32IC-LABEL: xor:
+; RV32IC-NEXT: c.xor a0, a1
+; RV32IC-NEXT: c.jr ra
%1 = xor i32 %a, %b
ret i32 %1
}
@@ -181,6 +219,10 @@ define i32 @and(i32 %a, i32 %b) nounwind {
; RV32I: # %bb.0:
; RV32I-NEXT: and a0, a0, a1
; RV32I-NEXT: ret
+
+; RV32IC-LABEL: and:
+; RV32IC-NEXT: c.and a0, a1
+; RV32IC-NEXT: c.jr ra
%1 = and i32 %a, %b
ret i32 %1
}
diff --git a/llvm/test/CodeGen/RISCV/branch.ll b/llvm/test/CodeGen/RISCV/branch.ll
index 53092c37561..f6d9299b07d 100644
--- a/llvm/test/CodeGen/RISCV/branch.ll
+++ b/llvm/test/CodeGen/RISCV/branch.ll
@@ -2,6 +2,11 @@
; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32I %s
+
+; RUN: llc -mtriple=riscv32 -mattr=+c -filetype=obj < %s \
+; RUN: |llvm-objdump -d -triple=riscv32 -mattr=+c -riscv-no-aliases - \
+; RUN: | FileCheck -check-prefix=RV32IC %s
+
define void @foo(i32 %a, i32 *%b, i1 %c) {
; RV32I-LABEL: foo:
; RV32I: # %bb.0:
@@ -43,6 +48,33 @@ define void @foo(i32 %a, i32 *%b, i1 %c) {
; RV32I-NEXT: .LBB0_12: # %end
; RV32I-NEXT: ret
+; RV32IC-LABEL: foo:
+; RV32IC: c.lw a3, 0(a1)
+; RV32IC-NEXT: beq a3, a0, 68
+; RV32IC-NEXT: c.lw a3, 0(a1)
+; RV32IC-NEXT: bne a3, a0, 62
+; RV32IC-NEXT: c.lw a3, 0(a1)
+; RV32IC-NEXT: blt a3, a0, 56
+; RV32IC-NEXT: c.lw a3, 0(a1)
+; RV32IC-NEXT: bge a3, a0, 50
+; RV32IC-NEXT: c.lw a3, 0(a1)
+; RV32IC-NEXT: bltu a3, a0, 44
+; RV32IC-NEXT: c.lw a3, 0(a1)
+; RV32IC-NEXT: bgeu a3, a0, 38
+; RV32IC-NEXT: c.lw a3, 0(a1)
+; RV32IC-NEXT: blt a0, a3, 32
+; RV32IC-NEXT: c.lw a3, 0(a1)
+; RV32IC-NEXT: bge a0, a3, 26
+; RV32IC-NEXT: c.lw a3, 0(a1)
+; RV32IC-NEXT: bltu a0, a3, 20
+; RV32IC-NEXT: c.lw a3, 0(a1)
+; RV32IC-NEXT: bgeu a0, a3, 14
+; RV32IC-NEXT: c.lw a0, 0(a1)
+; RV32IC-NEXT: andi a0, a2, 1
+; RV32IC-NEXT: c.bnez a0, 4
+; RV32IC-NEXT: c.lw a0, 0(a1)
+; RV32IC-NEXT: c.jr ra
+
%val1 = load volatile i32, i32* %b
%tst1 = icmp eq i32 %val1, %a
br i1 %tst1, label %end, label %test2
diff --git a/llvm/test/CodeGen/RISCV/compress-Pseudo.ll b/llvm/test/CodeGen/RISCV/compress-Pseudo.ll
new file mode 100644
index 00000000000..bb25fe9d51d
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/compress-Pseudo.ll
@@ -0,0 +1,10 @@
+; RUN: llc -mtriple=riscv32 -mattr=+c -riscv-no-aliases -o %t1 < %s
+; RUN: FileCheck %s < %t1
+
+define void @foo() {
+; CHECK-LABEL: foo:
+; CHECK: c.jr
+
+end:
+ ret void
+}
diff --git a/llvm/test/CodeGen/RISCV/compress-inline-asm.ll b/llvm/test/CodeGen/RISCV/compress-inline-asm.ll
new file mode 100644
index 00000000000..9b84bdeaf5d
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/compress-inline-asm.ll
@@ -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
+
+@ext = external global i32
+
+define i32 @compress_test(i32 %a) {
+; CHECK-LABEL: compress_test:
+; CHECK: c.add a0, a1
+; CHECK-NEXT: c.jr ra
+ %1 = load i32, i32* @ext
+ %2 = tail call i32 asm "add $0, $1, $2", "=r,r,r"(i32 %a, i32 %1)
+ ret i32 %2
+}
+
diff --git a/llvm/test/MC/RISCV/cnop.s b/llvm/test/MC/RISCV/cnop.s
index 2a2755f55e1..1ac75ec7892 100644
--- a/llvm/test/MC/RISCV/cnop.s
+++ b/llvm/test/MC/RISCV/cnop.s
@@ -1,5 +1,5 @@
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \
-# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INST %s
+# RUN: | llvm-objdump -d -riscv-no-aliases - | FileCheck -check-prefix=CHECK-INST %s
# alpha and main are 8 byte alignment
# but the alpha function's size is 6
diff --git a/llvm/test/MC/RISCV/compress-cjal.s b/llvm/test/MC/RISCV/compress-cjal.s
new file mode 100644
index 00000000000..a77297f6947
--- /dev/null
+++ b/llvm/test/MC/RISCV/compress-cjal.s
@@ -0,0 +1,17 @@
+# RUN: llvm-mc -triple riscv32 -mattr=+c -show-encoding < %s \
+# RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s
+# RUN: llvm-mc -triple riscv32 -mattr=+c -show-encoding \
+# RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK,CHECK-INST %s
+# RUN: llvm-mc -triple riscv32 -mattr=+c -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 -mattr=+c -filetype=obj < %s \
+# RUN: | llvm-objdump -triple riscv32 -mattr=+c -d -riscv-no-aliases - \
+# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
+
+# c.jal is an rv32 only instruction.
+jal ra, 2046
+# CHECK-BYTES: fd 2f
+# CHECK-ALIAS: jal 2046
+# CHECK-INST: c.jal 2046
+# CHECK: # encoding: [0xfd,0x2f]
diff --git a/llvm/test/MC/RISCV/compress-rv32d.s b/llvm/test/MC/RISCV/compress-rv32d.s
new file mode 100644
index 00000000000..eac0321778e
--- /dev/null
+++ b/llvm/test/MC/RISCV/compress-rv32d.s
@@ -0,0 +1,44 @@
+# RUN: llvm-mc -triple riscv32 -mattr=+c,+d -show-encoding < %s \
+# RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s
+# RUN: llvm-mc -triple riscv32 -mattr=+c,+d -show-encoding \
+# RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK,CHECK-INST %s
+# RUN: llvm-mc -triple riscv32 -mattr=+c,+d -filetype=obj < %s \
+# RUN: | llvm-objdump -triple riscv32 -mattr=+c,+d -d - \
+# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
+# RUN: llvm-mc -triple riscv32 -mattr=+c,+d -filetype=obj < %s \
+# RUN: | llvm-objdump -triple riscv32 -mattr=+c,+d -d -riscv-no-aliases - \
+# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
+
+# RUN: llvm-mc -triple riscv64 -mattr=+c,+d -show-encoding < %s \
+# RUN: | FileCheck -check-prefixes=CHECK-ALIAS %s
+# RUN: llvm-mc -triple riscv64 -mattr=+c,+d -show-encoding \
+# RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK-INST %s
+# RUN: llvm-mc -triple riscv64 -mattr=+c,+d -filetype=obj < %s \
+# RUN: | llvm-objdump -triple riscv64 -mattr=+c,+d -d - \
+# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
+# RUN: llvm-mc -triple riscv64 -mattr=+c,+d -filetype=obj < %s \
+# RUN: | llvm-objdump -triple riscv64 -mattr=+c,+d -d -riscv-no-aliases - \
+# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
+
+# Tests double precision floating point instructions available in rv32 and in rv64.
+
+fld ft0, 64(sp)
+# CHECK-BYTES: 06 20
+# CHECK-ALIAS: fld ft0, 64(sp)
+# CHECK-INST: c.fldsp ft0, 64(sp)
+# CHECK: # encoding: [0x06,0x20]
+fsd ft0, 64(sp)
+# CHECK-BYTES: 82 a0
+# CHECK-ALIAS: fsd ft0, 64(sp)
+# CHECK-INST: c.fsdsp ft0, 64(sp)
+# CHECK: # encoding: [0x82,0xa0]
+fld fs0, 248(s0)
+# CHECK-BYTES: 60 3c
+# CHECK-ALIAS: fld fs0, 248(s0)
+# CHECK-INST: c.fld fs0, 248(s0)
+# CHECK: # encoding: [0x60,0x3c]
+fsd fs0, 248(s0)
+# CHECK-BYTES: 60 bc
+# CHECK-ALIAS: fsd fs0, 248(s0)
+# CHECK-INST: c.fsd fs0, 248(s0)
+# CHECK: # encoding: [0x60,0xbc]
diff --git a/llvm/test/MC/RISCV/compress-rv32f.s b/llvm/test/MC/RISCV/compress-rv32f.s
new file mode 100644
index 00000000000..482e528c9ee
--- /dev/null
+++ b/llvm/test/MC/RISCV/compress-rv32f.s
@@ -0,0 +1,32 @@
+# RUN: llvm-mc -triple riscv32 -mattr=+c,+f -show-encoding < %s \
+# RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s
+# RUN: llvm-mc -triple riscv32 -mattr=+c,+f -show-encoding \
+# RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK,CHECK-INST %s
+# RUN: llvm-mc -triple riscv32 -mattr=+c,+f -filetype=obj < %s \
+# RUN: | llvm-objdump -triple riscv32 -mattr=+c,+f -d - \
+# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-ALIAS %s
+# RUN: llvm-mc -triple riscv32 -mattr=+c,+f -filetype=obj < %s \
+# RUN: | llvm-objdump -triple riscv32 -mattr=+c,+f -d -riscv-no-aliases - \
+# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
+
+# Instructions that are 32 bit only.
+flw ft0, 124(sp)
+# CHECK-BYTES: 76 70
+# CHECK-ALIAS: flw ft0, 124(sp)
+# CHECK-INST: c.flwsp ft0, 124(sp)
+# CHECK: # encoding: [0x76,0x70]
+fsw ft0, 124(sp)
+# CHECK-BYTES: 82 fe
+# CHECK-ALIAS: fsw ft0, 124(sp)
+# CHECK-INST: c.fswsp ft0, 124(sp)
+# CHECK: # encoding: [0x82,0xfe]
+flw fs0, 124(s0)
+# CHECK-BYTES: 60 7c
+# CHECK-ALIAS: flw fs0, 124(s0)
+# CHECK-INST: c.flw fs0, 124(s0)
+# CHECK: # encoding: [0x60,0x7c]
+fsw fs0, 124(s0)
+# CHECK-BYTES: 60 fc
+# CHECK-ALIAS: fsw fs0, 124(s0)
+# CHECK-INST: c.fsw fs0, 124(s0)
+# CHECK: # encoding: [0x60,0xfc]
diff --git a/llvm/test/MC/RISCV/compress-rv32i.s b/llvm/test/MC/RISCV/compress-rv32i.s
new file mode 100644
index 00000000000..e368faf55d7
--- /dev/null
+++ b/llvm/test/MC/RISCV/compress-rv32i.s
@@ -0,0 +1,207 @@
+# RUN: llvm-mc -triple riscv32 -mattr=+c -show-encoding < %s \
+# RUN: | FileCheck -check-prefixes=CHECK,CHECK-ALIAS %s
+# RUN: llvm-mc -triple riscv32 -mattr=+c -show-encoding \
+# RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK,CHECK-INST %s
+# RUN: llvm-mc -triple riscv32 -mattr=+c -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 -mattr=+c -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 -mattr=+c -show-encoding < %s \
+# RUN: | FileCheck -check-prefixes=CHECK-ALIAS %s
+# RUN: llvm-mc -triple riscv64 -mattr=+c -show-encoding \
+# RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK-INST %s
+# RUN: llvm-mc -triple riscv64 -mattr=+c -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 -mattr=+c -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: e0 1f
+# CHECK-ALIAS: addi s0, sp, 1020
+# CHECK-INST: c.addi4spn s0, sp, 1020
+# CHECK: # encoding: [0xe0,0x1f]
+addi s0, sp, 1020
+
+# CHECK-BYTES: e0 5f
+# CHECK-ALIAS: lw s0, 124(a5)
+# CHECK-INST: c.lw s0, 124(a5)
+# CHECK: # encoding: [0xe0,0x5f]
+lw s0, 124(a5)
+
+# CHECK-BYTES: e0 df
+# CHECK-ALIAS: sw s0, 124(a5)
+# CHECK-INST: c.sw s0, 124(a5)
+# CHECK: # encoding: [0xe0,0xdf]
+sw s0, 124(a5)
+
+# CHECK-BYTES: 01 00
+# CHECK-ALIAS: nop
+# CHECK-INST: c.nop
+# CHECK: # encoding: [0x01,0x00]
+nop
+
+# CHECK-BYTES: 81 10
+# CHECK-ALIAS: addi ra, ra, -32
+# CHECK-INST: c.addi ra, -32
+# CHECK: # encoding: [0x81,0x10]
+addi ra, ra, -32
+
+# CHECK-BYTES: 85 50
+# CHECK-ALIAS: addi ra, zero, -31
+# CHECK-INST: c.li ra, -31
+# CHECK: # encoding: [0x85,0x50]
+addi ra, zero, -31
+
+# CHECK-BYTES: 39 71
+# CHECK-ALIAS: addi sp, sp, -64
+# CHECK-INST: c.addi16sp sp, -64
+# CHECK: # encoding: [0x39,0x71]
+addi sp, sp, -64
+
+# CHECK-BYTES: fd 61
+# CHECK-ALIAS: lui gp, 31
+# CHECK-INST: c.lui gp, 31
+# CHECK: # encoding: [0xfd,0x61]
+lui gp, 31
+
+# CHECK-BYTES: 7d 80
+# CHECK-ALIAS: srli s0, s0, 31
+# CHECK-INST: c.srli s0, 31
+# CHECK: # encoding: [0x7d,0x80]
+srli s0, s0, 31
+
+# CHECK-BYTES: 7d 84
+# CHECK-ALIAS: srai s0, s0, 31
+# CHECK-INST: c.srai s0, 31
+# CHECK: # encoding: [0x7d,0x84]
+srai s0, s0, 31
+
+# CHECK-BYTES: 7d 88
+# CHECK-ALIAS: andi s0, s0, 31
+# CHECK-INST: c.andi s0, 31
+# CHECK: # encoding: [0x7d,0x88]
+andi s0, s0, 31
+
+# CHECK-BYTES: 1d 8c
+# CHECK-ALIAS: sub s0, s0, a5
+# CHECK-INST: c.sub s0, a5
+# CHECK: # encoding: [0x1d,0x8c]
+sub s0, s0, a5
+
+# CHECK-BYTES: 3d 8c
+# CHECK-ALIAS: xor s0, s0, a5
+# CHECK-INST: c.xor s0, a5
+# CHECK: # encoding: [0x3d,0x8c]
+xor s0, s0, a5
+
+# CHECK-BYTES: 3d 8c
+# CHECK-ALIAS: xor s0, s0, a5
+# CHECK-INST: c.xor s0, a5
+# CHECK: # encoding: [0x3d,0x8c]
+xor s0, a5, s0
+
+# CHECK-BYTES: 5d 8c
+# CHECK-ALIAS: or s0, s0, a5
+# CHECK-INST: c.or s0, a5
+# CHECK: # encoding: [0x5d,0x8c]
+or s0, s0, a5
+
+# CHECK-BYTES: 45 8c
+# CHECK-ALIAS: or s0, s0, s1
+# CHECK-INST: c.or s0, s1
+# CHECK: # encoding: [0x45,0x8c]
+or s0, s1, s0
+
+# CHECK-BYTES: 7d 8c
+# CHECK-ALIAS: and s0, s0, a5
+# CHECK-INST: c.and s0, a5
+# CHECK: # encoding: [0x7d,0x8c]
+and s0, s0, a5
+
+# CHECK-BYTES: 7d 8c
+# CHECK-ALIAS: and s0, s0, a5
+# CHECK-INST: c.and s0, a5
+# CHECK: # encoding: [0x7d,0x8c]
+and s0, a5, s0
+
+# CHECK-BYTES: 01 b0
+# CHECK-ALIAS: j -2048
+# CHECK-INST: c.j -2048
+# CHECK: # encoding: [0x01,0xb0]
+jal zero, -2048
+
+# CHECK-BYTES: 01 d0
+# CHECK-ALIAS: beqz s0, -256
+# CHECK-INST: c.beqz s0, -256
+# CHECK: # encoding: [0x01,0xd0]
+beq s0, zero, -256
+
+# CHECK-BYTES: 7d ec
+# CHECk-ALIAS: bnez s0, 254
+# CHECK-INST: c.bnez s0, 254
+# CHECK: # encoding: [0x7d,0xec]
+bne s0, zero, 254
+
+# CHECK-BYTES: 7e 04
+# CHECK-ALIAS: slli s0, s0, 31
+# CHECK-INST: c.slli s0, 31
+# CHECK: # encoding: [0x7e,0x04]
+slli s0, s0, 31
+
+# CHECK-BYTES: fe 50
+# CHECK-ALIAS: lw ra, 252(sp)
+# CHECK-INST: c.lwsp ra, 252(sp)
+# CHECK: # encoding: [0xfe,0x50]
+lw ra, 252(sp)
+
+# CHECK-BYTES: 82 80
+# CHECK-ALIAS: ret
+# CHECK-INST: c.jr ra
+# CHECK: # encoding: [0x82,0x80]
+jalr zero, ra, 0
+
+# CHECK-BYTES: 92 80
+# CHECK-ALIAS: add ra, zero, tp
+# CHECK-INST: c.mv ra, tp
+# CHECK: # encoding: [0x92,0x80]
+add ra, zero, tp
+
+# CHECK-BYTES: 92 80
+# CHECK-ALIAS: add ra, zero, tp
+# CHECK-INST: c.mv ra, tp
+# CHECK: # encoding: [0x92,0x80]
+add ra, tp, zero
+
+# CHECK-BYTES: 02 90
+# CHECK-ALIAS: ebreak
+# CHECK-INST: c.ebreak
+# CHECK: # encoding: [0x02,0x90]
+ebreak
+
+# CHECK-BYTES: 02 94
+# CHECK-ALIAS: jalr s0
+# CHECK-INST: c.jalr s0
+# CHECK: # encoding: [0x02,0x94]
+jalr ra, s0, 0
+
+# CHECK-BYTES: 3e 94
+# CHECK-ALIAS: add s0, s0, a5
+# CHECK-INST: c.add s0, a5
+# CHECK: # encoding: [0x3e,0x94]
+add s0, a5, s0
+
+# CHECK-BYTES: 3e 94
+# CHECK-ALIAS: add s0, s0, a5
+# CHECK-INST: c.add s0, a5
+# CHECK: # encoding: [0x3e,0x94]
+add s0, s0, a5
+
+# CHECK-BYTES: 82 df
+# CHECK-ALIAS: sw zero, 252(sp)
+# CHECK-INST: c.swsp zero, 252(sp)
+# CHECK: # encoding: [0x82,0xdf]
+sw zero, 252(sp)
diff --git a/llvm/test/MC/RISCV/compress-rv64i.s b/llvm/test/MC/RISCV/compress-rv64i.s
new file mode 100644
index 00000000000..7e887ff80d6
--- /dev/null
+++ b/llvm/test/MC/RISCV/compress-rv64i.s
@@ -0,0 +1,60 @@
+# RUN: llvm-mc -triple riscv64 -mattr=+c -show-encoding < %s \
+# RUN: | FileCheck -check-prefixes=CHECK-ALIAS %s
+# RUN: llvm-mc -triple riscv64 -mattr=+c -show-encoding \
+# RUN: -riscv-no-aliases <%s | FileCheck -check-prefixes=CHECK-INST %s
+# RUN: llvm-mc -triple riscv64 -mattr=+c -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 -mattr=+c -filetype=obj < %s \
+# RUN: | llvm-objdump -triple riscv64 -mattr=+c -d -riscv-no-aliases - \
+# RUN: | FileCheck -check-prefixes=CHECK-BYTES,CHECK-INST %s
+
+# Tests compressed instructions available in rv64 and not in rv32.
+
+# CHECK-BYTES: e0 7f
+# CHECK-ALIAS: ld s0, 248(a5)
+# CHECK-INST: c.ld s0, 248(a5)
+# CHECK: # encoding: [0xe0,0x7f]
+ld s0, 248(a5)
+
+# CHECK-BYTES: a0 e3
+# CHECK-ALIAS: sd s0, 64(a5)
+# CHECK-INST: c.sd s0, 64(a5)
+# CHECK: # encoding: [0xa0,0xe3]
+sd s0, 64(a5)
+
+# CHECK-BYTES: 7d 22
+# CHEACK-ALIAS: addiw tp, tp, 31
+# CHECK-INST: c.addiw tp, 31
+# CHECK: # encoding: [0x7d,0x22]
+addiw tp, tp, 31
+
+# CHECK-BYTES: 1d 9c
+# CHEACK-ALIAS: subw s0, s0, a5
+# CHECK-INST: c.subw s0, a5
+# CHECK: # encoding: [0x1d,0x9c]
+subw s0, s0, a5
+
+# CHECK-BYTES: 3d 9c
+# CHECK-ALIAS: addw s0, s0, a5
+# CHECK-INST: c.addw s0, a5
+# CHECK: # encoding: [0x3d,0x9c]
+addw s0, s0, a5
+
+# CHECK-BYTES: 3d 9c
+# CHECK-ALIAS: addw s0, s0, a5
+# CHECK-INST: c.addw s0, a5
+# CHECK: # encoding: [0x3d,0x9c]
+addw s0, a5, s0
+
+# CHECK-BYTES: ee 70
+# CHECK-ALIAS: ld ra, 248(sp)
+# CHECK-INST: c.ldsp ra, 248(sp)
+# CHECK: # encoding: [0xee,0x70]
+ld ra, 248(sp)
+
+# CHECK-BYTES: a2 e0
+# CHECK-ALIAS: sd s0, 64(sp)
+# CHECK-INST: c.sdsp s0, 64(sp)
+# CHECK: # encoding: [0xa2,0xe0]
+sd s0, 64(sp)
diff --git a/llvm/test/MC/RISCV/compressed-relocations.s b/llvm/test/MC/RISCV/compressed-relocations.s
new file mode 100644
index 00000000000..832a2085e61
--- /dev/null
+++ b/llvm/test/MC/RISCV/compressed-relocations.s
@@ -0,0 +1,20 @@
+# RUN: llvm-mc -triple riscv32 -mattr=+c -riscv-no-aliases < %s -show-encoding \
+# RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
+# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \
+# RUN: | llvm-readobj -r | FileCheck -check-prefix=RELOC %s
+
+# Check prefixes:
+# RELOC - Check the relocation in the object.
+# FIXUP - Check the fixup on the instruction.
+# INSTR - Check the instruction is handled properly by the ASMPrinter
+c.jal foo
+# A compressed jump (c.j) to an unresolved symbol will be relaxed to a (jal).
+# RELOC: R_RISCV_JAL
+# INSTR: c.jal foo
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_rvc_jump
+
+c.bnez a0, foo
+# A compressed branch (c.bnez) to an unresolved symbol will be relaxed to a (bnez).
+# RELOC: R_RISCV_BRANCH
+# INSTR: c.bnez a0, foo
+# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_rvc_branch
diff --git a/llvm/test/MC/RISCV/fixups-compressed.s b/llvm/test/MC/RISCV/fixups-compressed.s
index a97d290f216..7ae6274bf27 100644
--- a/llvm/test/MC/RISCV/fixups-compressed.s
+++ b/llvm/test/MC/RISCV/fixups-compressed.s
@@ -1,7 +1,7 @@
# RUN: llvm-mc %s -triple riscv32 -mattr=+c -show-encoding \
# RUN: | FileCheck -check-prefix=CHECK-FIXUP %s
# RUN: llvm-mc -triple riscv32 -filetype=obj -mattr=+c < %s \
-# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INSTR %s
+# RUN: | llvm-objdump -d -riscv-no-aliases - | FileCheck -check-prefix=CHECK-INSTR %s
# RUN: llvm-mc -filetype=obj -mattr=+c -triple=riscv32 %s \
# RUN: | llvm-readobj -r | FileCheck %s -check-prefix=CHECK-REL
diff --git a/llvm/test/MC/RISCV/relocations.s b/llvm/test/MC/RISCV/relocations.s
index 77421620e68..b68b11bf195 100644
--- a/llvm/test/MC/RISCV/relocations.s
+++ b/llvm/test/MC/RISCV/relocations.s
@@ -1,4 +1,4 @@
-# RUN: llvm-mc -triple riscv32 -mattr=+c -riscv-no-aliases < %s -show-encoding \
+# RUN: llvm-mc -triple riscv32 -riscv-no-aliases < %s -show-encoding \
# RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \
# RUN: | llvm-readobj -r | FileCheck -check-prefix=RELOC %s
@@ -83,15 +83,3 @@ bgeu a0, a1, foo
# RELOC: R_RISCV_BRANCH
# INSTR: bgeu a0, a1, foo
# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_branch
-
-c.jal foo
-# A compressed jump (c.j) to an unresolved symbol will be relaxed to a (jal).
-# RELOC: R_RISCV_JAL
-# INSTR: c.jal foo
-# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_rvc_jump
-
-c.bnez a0, foo
-# A compressed branch (c.bnez) to an unresolved symbol will be relaxed to a (bnez).
-# RELOC: R_RISCV_BRANCH
-# INSTR: c.bnez a0, foo
-# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_rvc_branch
diff --git a/llvm/test/MC/RISCV/rv32-relaxation.s b/llvm/test/MC/RISCV/rv32-relaxation.s
index 66109faf3eb..8b1675d3389 100644
--- a/llvm/test/MC/RISCV/rv32-relaxation.s
+++ b/llvm/test/MC/RISCV/rv32-relaxation.s
@@ -1,5 +1,5 @@
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \
-# RUN: | llvm-objdump -d - | FileCheck -check-prefix=INSTR %s
+# RUN: | llvm-objdump -d -riscv-no-aliases - | FileCheck -check-prefix=INSTR %s
FAR_JUMP_NEGATIVE:
c.nop
@@ -18,26 +18,26 @@ start:
c.bnez a0, NEAR_NEGATIVE
#INSTR: c.bnez a0, -4
c.bnez a0, FAR_BRANCH
-#INSTR-NEXT: bnez a0, 326
+#INSTR-NEXT: bne a0, zero, 326
c.bnez a0, FAR_BRANCH_NEGATIVE
-#INSTR-NEXT: bnez a0, -268
+#INSTR-NEXT: bne a0, zero, -268
c.bnez a0, FAR_JUMP
-#INSTR-NEXT: bnez a0, 2320
+#INSTR-NEXT: bne a0, zero, 2320
c.bnez a0, FAR_JUMP_NEGATIVE
-#INSTR-NEXT: bnez a0, -2278
+#INSTR-NEXT: bne a0, zero, -2278
c.beqz a0, NEAR
#INSTR-NEXT: c.beqz a0, 52
c.beqz a0, NEAR_NEGATIVE
#INSTR-NEXT: c.beqz a0, -24
c.beqz a0, FAR_BRANCH
-#INSTR-NEXT: beqz a0, 306
+#INSTR-NEXT: beq a0, zero, 306
c.beqz a0, FAR_BRANCH_NEGATIVE
-#INSTR-NEXT: beqz a0, -288
+#INSTR-NEXT: beq a0, zero, -288
c.beqz a0, FAR_JUMP
-#INSTR-NEXT: beqz a0, 2300
+#INSTR-NEXT: beq a0, zero, 2300
c.beqz a0, FAR_JUMP_NEGATIVE
-#INSTR-NEXT: beqz a0, -2298
+#INSTR-NEXT: beq a0, zero, -2298
c.j NEAR
#INSTR-NEXT: c.j 32
@@ -48,9 +48,9 @@ start:
c.j FAR_BRANCH_NEGATIVE
#INSTR-NEXT: c.j -306
c.j FAR_JUMP
-#INSTR-NEXT: j 2284
+#INSTR-NEXT: jal zero, 2284
c.j FAR_JUMP_NEGATIVE
-#INSTR-NEXT: j -2314
+#INSTR-NEXT: jal zero, -2314
c.jal NEAR
#INSTR: c.jal 16
@@ -61,9 +61,9 @@ start:
c.jal FAR_BRANCH_NEGATIVE
#INSTR-NEXT: c.jal -322
c.jal FAR_JUMP
-#INSTR-NEXT: jal 2268
+#INSTR-NEXT: jal ra, 2268
c.jal FAR_JUMP_NEGATIVE
-#INSTR-NEXT: jal -2330
+#INSTR-NEXT: jal ra, -2330
NEAR:
c.nop
diff --git a/llvm/test/MC/RISCV/rv64-relaxation.s b/llvm/test/MC/RISCV/rv64-relaxation.s
index 018408f575a..f0551244665 100644
--- a/llvm/test/MC/RISCV/rv64-relaxation.s
+++ b/llvm/test/MC/RISCV/rv64-relaxation.s
@@ -1,5 +1,5 @@
# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c < %s \
-# RUN: | llvm-objdump -d - | FileCheck -check-prefix=INSTR %s
+# RUN: | llvm-objdump -d -riscv-no-aliases - | FileCheck -check-prefix=INSTR %s
FAR_JUMP_NEGATIVE:
c.nop
@@ -18,26 +18,26 @@ start:
c.bnez a0, NEAR_NEGATIVE
#INSTR: c.bnez a0, -4
c.bnez a0, FAR_BRANCH
-#INSTR-NEXT: bnez a0, 310
+#INSTR-NEXT: bne a0, zero, 310
c.bnez a0, FAR_BRANCH_NEGATIVE
-#INSTR-NEXT: bnez a0, -268
+#INSTR-NEXT: bne a0, zero, -268
c.bnez a0, FAR_JUMP
-#INSTR-NEXT: bnez a0, 2304
+#INSTR-NEXT: bne a0, zero, 2304
c.bnez a0, FAR_JUMP_NEGATIVE
-#INSTR-NEXT: bnez a0, -2278
+#INSTR-NEXT: bne a0, zero, -2278
c.beqz a0, NEAR
#INSTR-NEXT: c.beqz a0, 36
c.beqz a0, NEAR_NEGATIVE
#INSTR-NEXT: c.beqz a0, -24
c.beqz a0, FAR_BRANCH
-#INSTR-NEXT: beqz a0, 290
+#INSTR-NEXT: beq a0, zero, 290
c.beqz a0, FAR_BRANCH_NEGATIVE
-#INSTR-NEXT: beqz a0, -288
+#INSTR-NEXT: beq a0, zero, -288
c.beqz a0, FAR_JUMP
-#INSTR-NEXT: beqz a0, 2284
+#INSTR-NEXT: beq a0, zero, 2284
c.beqz a0, FAR_JUMP_NEGATIVE
-#INSTR-NEXT: beqz a0, -2298
+#INSTR-NEXT: beq a0, zero, -2298
c.j NEAR
#INSTR-NEXT: c.j 16
@@ -48,9 +48,9 @@ start:
c.j FAR_BRANCH_NEGATIVE
#INSTR-NEXT: c.j -306
c.j FAR_JUMP
-#INSTR-NEXT: j 2268
+#INSTR-NEXT: jal zero, 2268
c.j FAR_JUMP_NEGATIVE
-#INSTR-NEXT: j -2314
+#INSTR-NEXT: jal zero, -2314
NEAR:
c.nop
diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt
index 0944d54a427..36bad4441ac 100644
--- a/llvm/utils/TableGen/CMakeLists.txt
+++ b/llvm/utils/TableGen/CMakeLists.txt
@@ -30,6 +30,7 @@ add_tablegen(llvm-tblgen LLVM
IntrinsicEmitter.cpp
OptParserEmitter.cpp
PseudoLoweringEmitter.cpp
+ RISCVCompressInstEmitter.cpp
RegisterBankEmitter.cpp
RegisterInfoEmitter.cpp
SDNodeProperties.cpp
diff --git a/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp b/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp
new file mode 100644
index 00000000000..c362390a56d
--- /dev/null
+++ b/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp
@@ -0,0 +1,806 @@
+//===- RISCVCompressInstEmitter.cpp - Generator for RISCV Compression -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// RISCVCompressInstEmitter implements a tablegen-driven CompressPat based
+// RISCV Instruction Compression mechanism.
+//
+//===--------------------------------------------------------------===//
+//
+// RISCVCompressInstEmitter implements a tablegen-driven CompressPat Instruction
+// Compression mechanism for generating RISCV compressed instructions
+// (C ISA Extension) from the expanded instruction form.
+
+// This tablegen backend processes CompressPat declarations in a
+// td file and generates all the required checks to validate the pattern
+// declarations; validate the input and output operands to generate the correct
+// compressed instructions. The checks include validating different types of
+// operands; register operands, immediate operands, fixed register and fixed
+// immediate inputs.
+//
+// Example:
+// class CompressPat<dag input, dag output> {
+// dag Input = input;
+// dag Output = output;
+// list<Predicate> Predicates = [];
+// }
+//
+// let Predicates = [HasStdExtC] in {
+// def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs1, GPRNoX0:$rs2),
+// (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>;
+// }
+//
+// The result is an auto-generated header file
+// 'RISCVGenCompressInstEmitter.inc' which exports two functions for
+// compressing/uncompressing MCInst instructions, plus
+// some helper functions:
+//
+// bool compressInst(MCInst& OutInst, const MCInst &MI,
+// const MCSubtargetInfo &STI,
+// MCContext &Context);
+//
+// bool uncompressInst(MCInst& OutInst, const MCInst &MI,
+// const MCRegisterInfo &MRI,
+// const MCSubtargetInfo &STI);
+//
+// The clients that include this auto-generated header file and
+// invoke these functions can compress an instruction before emitting
+// it in the target-specific ASM or ELF streamer or can uncompress
+// an instruction before printing it when the expanded instruction
+// format aliases is favored.
+
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenInstruction.h"
+#include "CodeGenTarget.h"
+#include "llvm/ADT/IndexedMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <vector>
+using namespace llvm;
+
+#define DEBUG_TYPE "compress-inst-emitter"
+
+namespace {
+class RISCVCompressInstEmitter {
+ struct OpData {
+ enum MapKind { Operand, Imm, Reg };
+ MapKind Kind;
+ union {
+ unsigned Operand; // Operand number mapped to.
+ uint64_t Imm; // Integer immediate value.
+ Record *Reg; // Physical register.
+ } Data;
+ int TiedOpIdx = -1; // Tied operand index within the instruction.
+ };
+ struct CompressPat {
+ CodeGenInstruction Source; // The source instruction definition.
+ CodeGenInstruction Dest; // The destination instruction to transform to.
+ std::vector<Record *>
+ PatReqFeatures; // Required target features to enable pattern.
+ IndexedMap<OpData>
+ SourceOperandMap; // Maps operands in the Source Instruction to
+ // the corresponding Dest instruction operand.
+ IndexedMap<OpData>
+ DestOperandMap; // Maps operands in the Dest Instruction
+ // to the corresponding Source instruction operand.
+ CompressPat(CodeGenInstruction &S, CodeGenInstruction &D,
+ std::vector<Record *> RF, IndexedMap<OpData> &SourceMap,
+ IndexedMap<OpData> &DestMap)
+ : Source(S), Dest(D), PatReqFeatures(RF), SourceOperandMap(SourceMap),
+ DestOperandMap(DestMap) {}
+ };
+
+ RecordKeeper &Records;
+ CodeGenTarget Target;
+ SmallVector<CompressPat, 4> CompressPatterns;
+
+ void addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Inst,
+ IndexedMap<OpData> &OperandMap, bool IsSourceInst);
+ void evaluateCompressPat(Record *Compress);
+ void emitCompressInstEmitter(raw_ostream &o, bool Compress);
+ bool validateTypes(Record *SubType, Record *Type, bool IsSourceInst);
+ bool validateRegister(Record *Reg, Record *RegClass);
+ void createDagOperandMapping(Record *Rec, StringMap<unsigned> &SourceOperands,
+ StringMap<unsigned> &DestOperands,
+ DagInit *SourceDag, DagInit *DestDag,
+ IndexedMap<OpData> &SourceOperandMap);
+
+ void createInstOperandMapping(Record *Rec, DagInit *SourceDag,
+ DagInit *DestDag,
+ IndexedMap<OpData> &SourceOperandMap,
+ IndexedMap<OpData> &DestOperandMap,
+ StringMap<unsigned> &SourceOperands,
+ CodeGenInstruction &DestInst);
+
+public:
+ RISCVCompressInstEmitter(RecordKeeper &R) : Records(R), Target(R) {}
+
+ void run(raw_ostream &o);
+};
+} // End anonymous namespace.
+
+bool RISCVCompressInstEmitter::validateRegister(Record *Reg, Record *RegClass) {
+ assert(Reg->isSubClassOf("Register") && "Reg record should be a Register\n");
+ assert(RegClass->isSubClassOf("RegisterClass") && "RegClass record should be"
+ " a RegisterClass\n");
+ CodeGenRegisterClass RC = Target.getRegisterClass(RegClass);
+ const CodeGenRegister *R = Target.getRegisterByName(Reg->getName().lower());
+ assert((R != nullptr) &&
+ ("Register" + Reg->getName().str() + " not defined!!\n").c_str());
+ return RC.contains(R);
+}
+
+bool RISCVCompressInstEmitter::validateTypes(Record *DagOpType,
+ Record *InstOpType,
+ bool IsSourceInst) {
+ if (DagOpType == InstOpType)
+ return true;
+ // Only source instruction operands are allowed to not match Input Dag
+ // operands.
+ if (!IsSourceInst)
+ return false;
+
+ if (DagOpType->isSubClassOf("RegisterClass") &&
+ InstOpType->isSubClassOf("RegisterClass")) {
+ CodeGenRegisterClass RC = Target.getRegisterClass(InstOpType);
+ CodeGenRegisterClass SubRC = Target.getRegisterClass(DagOpType);
+ return RC.hasSubClass(&SubRC);
+ }
+
+ // At this point either or both types are not registers, reject the pattern.
+ if (DagOpType->isSubClassOf("RegisterClass") ||
+ InstOpType->isSubClassOf("RegisterClass"))
+ return false;
+
+ // Let further validation happen when compress()/uncompress() functions are
+ // invoked.
+ DEBUG(dbgs() << (IsSourceInst ? "Input" : "Output") << " Dag Operand Type: '"
+ << DagOpType->getName() << "' and "
+ << "Instruction Operand Type: '" << InstOpType->getName()
+ << "' can't be checked at pattern validation time!\n");
+ return true;
+}
+
+/// The patterns in the Dag contain different types of operands:
+/// Register operands, e.g.: GPRC:$rs1; Fixed registers, e.g: X1; Immediate
+/// operands, e.g.: simm6:$imm; Fixed immediate operands, e.g.: 0. This function
+/// maps Dag operands to its corresponding instruction operands. For register
+/// operands and fixed registers it expects the Dag operand type to be contained
+/// in the instantiated instruction operand type. For immediate operands and
+/// immediates no validation checks are enforced at pattern validation time.
+void RISCVCompressInstEmitter::addDagOperandMapping(
+ Record *Rec, DagInit *Dag, CodeGenInstruction &Inst,
+ IndexedMap<OpData> &OperandMap, bool IsSourceInst) {
+ // TiedCount keeps track of the number of operands skipped in Inst
+ // operands list to get to the corresponding Dag operand. This is
+ // necessary because the number of operands in Inst might be greater
+ // than number of operands in the Dag due to how tied operands
+ // are represented.
+ unsigned TiedCount = 0;
+ for (unsigned i = 0, e = Inst.Operands.size(); i != e; ++i) {
+ int TiedOpIdx = Inst.Operands[i].getTiedRegister();
+ if (-1 != TiedOpIdx) {
+ // Set the entry in OperandMap for the tied operand we're skipping.
+ OperandMap[i].Kind = OperandMap[TiedOpIdx].Kind;
+ OperandMap[i].Data = OperandMap[TiedOpIdx].Data;
+ TiedCount++;
+ continue;
+ }
+ if (DefInit *DI = dyn_cast<DefInit>(Dag->getArg(i - TiedCount))) {
+ if (DI->getDef()->isSubClassOf("Register")) {
+ // Check if the fixed register belongs to the Register class.
+ if (!validateRegister(DI->getDef(), Inst.Operands[i].Rec))
+ PrintFatalError(Rec->getLoc(),
+ "Error in Dag '" + Dag->getAsString() +
+ "'Register: '" + DI->getDef()->getName() +
+ "' is not in register class '" +
+ Inst.Operands[i].Rec->getName() + "'");
+ OperandMap[i].Kind = OpData::Reg;
+ OperandMap[i].Data.Reg = DI->getDef();
+ continue;
+ }
+ // Validate that Dag operand type matches the type defined in the
+ // corresponding instruction. Operands in the input Dag pattern are
+ // allowed to be a subclass of the type specified in corresponding
+ // instruction operand instead of being an exact match.
+ if (!validateTypes(DI->getDef(), Inst.Operands[i].Rec, IsSourceInst))
+ PrintFatalError(Rec->getLoc(),
+ "Error in Dag '" + Dag->getAsString() + "'. Operand '" +
+ Dag->getArgNameStr(i - TiedCount) + "' has type '" +
+ DI->getDef()->getName() +
+ "' which does not match the type '" +
+ Inst.Operands[i].Rec->getName() +
+ "' in the corresponding instruction operand!");
+
+ OperandMap[i].Kind = OpData::Operand;
+ } else if (IntInit *II = dyn_cast<IntInit>(Dag->getArg(i - TiedCount))) {
+ // Validate that corresponding instruction operand expects an immediate.
+ if (Inst.Operands[i].Rec->isSubClassOf("RegisterClass"))
+ PrintFatalError(
+ Rec->getLoc(),
+ ("Error in Dag '" + Dag->getAsString() + "' Found immediate: '" +
+ II->getAsString() +
+ "' but corresponding instruction operand expected a register!"));
+ // No pattern validation check possible for values of fixed immediate.
+ OperandMap[i].Kind = OpData::Imm;
+ OperandMap[i].Data.Imm = II->getValue();
+ DEBUG(dbgs() << " Found immediate '" << II->getValue() << "' at "
+ << (IsSourceInst ? "input " : "output ")
+ << "Dag. No validation time check possible for values of "
+ "fixed immediate.\n");
+ } else
+ llvm_unreachable("Unhandled CompressPat argument type!");
+ }
+}
+
+// Verify the Dag operand count is enough to build an instruction.
+static bool verifyDagOpCount(CodeGenInstruction &Inst, DagInit *Dag,
+ bool IsSource) {
+ if (Dag->getNumArgs() == Inst.Operands.size())
+ return true;
+ // Source instructions are non compressed instructions and don't have tied
+ // operands.
+ if (IsSource)
+ PrintFatalError("Input operands for Inst '" + Inst.TheDef->getName() +
+ "' and input Dag operand count mismatch");
+ // The Dag can't have more arguments than the Instruction.
+ if (Dag->getNumArgs() > Inst.Operands.size())
+ PrintFatalError("Inst '" + Inst.TheDef->getName() +
+ "' and Dag operand count mismatch");
+
+ // The Instruction might have tied operands so the Dag might have
+ // a fewer operand count.
+ unsigned RealCount = Inst.Operands.size();
+ for (unsigned i = 0; i < Inst.Operands.size(); i++)
+ if (Inst.Operands[i].getTiedRegister() != -1)
+ --RealCount;
+
+ if (Dag->getNumArgs() != RealCount)
+ PrintFatalError("Inst '" + Inst.TheDef->getName() +
+ "' and Dag operand count mismatch");
+ return true;
+}
+
+static bool validateArgsTypes(Init *Arg1, Init *Arg2) {
+ DefInit *Type1 = dyn_cast<DefInit>(Arg1);
+ DefInit *Type2 = dyn_cast<DefInit>(Arg2);
+ assert(Type1 && ("Arg1 type not found\n"));
+ assert(Type2 && ("Arg2 type not found\n"));
+ return Type1->getDef() == Type2->getDef();
+}
+
+// Creates a mapping between the operand name in the Dag (e.g. $rs1) and
+// its index in the list of Dag operands and checks that operands with the same
+// name have the same types. For example in 'C_ADD $rs1, $rs2' we generate the
+// mapping $rs1 --> 0, $rs2 ---> 1. If the operand appears twice in the (tied)
+// same Dag we use the last occurrence for indexing.
+void RISCVCompressInstEmitter::createDagOperandMapping(
+ Record *Rec, StringMap<unsigned> &SourceOperands,
+ StringMap<unsigned> &DestOperands, DagInit *SourceDag, DagInit *DestDag,
+ IndexedMap<OpData> &SourceOperandMap) {
+ for (unsigned i = 0; i < DestDag->getNumArgs(); ++i) {
+ // Skip fixed immediates and registers, they were handled in
+ // addDagOperandMapping.
+ if ("" == DestDag->getArgNameStr(i))
+ continue;
+ DestOperands[DestDag->getArgNameStr(i)] = i;
+ }
+
+ for (unsigned i = 0; i < SourceDag->getNumArgs(); ++i) {
+ // Skip fixed immediates and registers, they were handled in
+ // addDagOperandMapping.
+ if ("" == SourceDag->getArgNameStr(i))
+ continue;
+
+ StringMap<unsigned>::iterator it =
+ SourceOperands.find(SourceDag->getArgNameStr(i));
+ if (it != SourceOperands.end()) {
+ // Operand sharing the same name in the Dag should be mapped as tied.
+ SourceOperandMap[i].TiedOpIdx = it->getValue();
+ if (!validateArgsTypes(SourceDag->getArg(it->getValue()),
+ SourceDag->getArg(i)))
+ PrintFatalError(Rec->getLoc(),
+ "Input Operand '" + SourceDag->getArgNameStr(i) +
+ "' has a mismatched tied operand!\n");
+ }
+ it = DestOperands.find(SourceDag->getArgNameStr(i));
+ if (it == DestOperands.end())
+ PrintFatalError(Rec->getLoc(), "Operand " + SourceDag->getArgNameStr(i) +
+ " defined in Input Dag but not used in"
+ " Output Dag!\n");
+ // Input Dag operand types must match output Dag operand type.
+ if (!validateArgsTypes(DestDag->getArg(it->getValue()),
+ SourceDag->getArg(i)))
+ PrintFatalError(Rec->getLoc(), "Type mismatch between Input and "
+ "Output Dag operand '" +
+ SourceDag->getArgNameStr(i) + "'!");
+ SourceOperands[SourceDag->getArgNameStr(i)] = i;
+ }
+}
+
+/// Map operand names in the Dag to their index in both corresponding input and
+/// output instructions. Validate that operands defined in the input are
+/// used in the output pattern while populating the maps.
+void RISCVCompressInstEmitter::createInstOperandMapping(
+ Record *Rec, DagInit *SourceDag, DagInit *DestDag,
+ IndexedMap<OpData> &SourceOperandMap, IndexedMap<OpData> &DestOperandMap,
+ StringMap<unsigned> &SourceOperands, CodeGenInstruction &DestInst) {
+ // TiedCount keeps track of the number of operands skipped in Inst
+ // operands list to get to the corresponding Dag operand.
+ unsigned TiedCount = 0;
+ DEBUG(dbgs() << " Operand mapping:\n Source Dest\n");
+ for (unsigned i = 0, e = DestInst.Operands.size(); i != e; ++i) {
+ int TiedInstOpIdx = DestInst.Operands[i].getTiedRegister();
+ if (TiedInstOpIdx != -1) {
+ ++TiedCount;
+ DestOperandMap[i].Data = DestOperandMap[TiedInstOpIdx].Data;
+ DestOperandMap[i].Kind = DestOperandMap[TiedInstOpIdx].Kind;
+ if (DestOperandMap[i].Kind == OpData::Operand)
+ // No need to fill the SourceOperandMap here since it was mapped to
+ // destination operand 'TiedInstOpIdx' in a previous iteration.
+ DEBUG(dbgs() << " " << DestOperandMap[i].Data.Operand << " ====> "
+ << i << " Dest operand tied with operand '"
+ << TiedInstOpIdx << "'\n");
+ continue;
+ }
+ // Skip fixed immediates and registers, they were handled in
+ // addDagOperandMapping.
+ if (DestOperandMap[i].Kind != OpData::Operand)
+ continue;
+
+ unsigned DagArgIdx = i - TiedCount;
+ StringMap<unsigned>::iterator SourceOp =
+ SourceOperands.find(DestDag->getArgNameStr(DagArgIdx));
+ if (SourceOp == SourceOperands.end())
+ PrintFatalError(Rec->getLoc(),
+ "Output Dag operand '" +
+ DestDag->getArgNameStr(DagArgIdx) +
+ "' has no matching input Dag operand.");
+
+ assert(DestDag->getArgNameStr(DagArgIdx) ==
+ SourceDag->getArgNameStr(SourceOp->getValue()) &&
+ "Incorrect operand mapping detected!\n");
+ DestOperandMap[i].Data.Operand = SourceOp->getValue();
+ SourceOperandMap[SourceOp->getValue()].Data.Operand = i;
+ DEBUG(dbgs() << " " << SourceOp->getValue() << " ====> " << i << "\n");
+ }
+}
+
+/// Validates the CompressPattern and create operand mapping.
+/// These are the checks to validate a CompressPat pattern declarations.
+/// Error out with message under these conditions:
+/// - Dag Input opcode is an expanded instruction and Dag Output opcode is a
+/// compressed instruction.
+/// - Operands in Dag Input must be all used in Dag Output.
+/// Register Operand type in Dag Input Type must be contained in the
+/// corresponding Source Instruction type.
+/// - Register Operand type in Dag Input must be the same as in Dag Ouput.
+/// - Register Operand type in Dag Output must be the same as the
+/// corresponding Destination Inst type.
+/// - Immediate Operand type in Dag Input must be the same as in Dag Ouput.
+/// - Immediate Operand type in Dag Ouput must be the same as the corresponding
+/// Destination Instruction type.
+/// - Fixed register must be contained in the corresponding Source Instruction
+/// type.
+/// - Fixed register must be contained in the corresponding Destination
+/// Instruction type. Warning message printed under these conditions:
+/// - Fixed immediate in Dag Input or Dag Ouput cannot be checked at this time
+/// and generate warning.
+/// - Immediate operand type in Dag Input differs from the corresponding Source
+/// Instruction type and generate a warning.
+void RISCVCompressInstEmitter::evaluateCompressPat(Record *Rec) {
+ // Validate input Dag operands.
+ DagInit *SourceDag = Rec->getValueAsDag("Input");
+ assert(SourceDag && "Missing 'Input' in compress pattern!");
+ DEBUG(dbgs() << "Input: " << *SourceDag << "\n");
+
+ DefInit *OpDef = dyn_cast<DefInit>(SourceDag->getOperator());
+ if (!OpDef)
+ PrintFatalError(Rec->getLoc(),
+ Rec->getName() + " has unexpected operator type!");
+ // Checking we are transforming from compressed to uncompressed instructions.
+ Record *Operator = OpDef->getDef();
+ if (!Operator->isSubClassOf("RVInst"))
+ PrintFatalError(Rec->getLoc(), "Input instruction '" + Operator->getName() +
+ "' is not a 32 bit wide instruction!");
+ CodeGenInstruction SourceInst(Operator);
+ verifyDagOpCount(SourceInst, SourceDag, true);
+
+ // Validate output Dag operands.
+ DagInit *DestDag = Rec->getValueAsDag("Output");
+ assert(DestDag && "Missing 'Output' in compress pattern!");
+ DEBUG(dbgs() << "Output: " << *DestDag << "\n");
+
+ DefInit *DestOpDef = dyn_cast<DefInit>(DestDag->getOperator());
+ if (!DestOpDef)
+ PrintFatalError(Rec->getLoc(),
+ Rec->getName() + " has unexpected operator type!");
+
+ Record *DestOperator = DestOpDef->getDef();
+ if (!DestOperator->isSubClassOf("RVInst16"))
+ PrintFatalError(Rec->getLoc(), "Output instruction '" +
+ DestOperator->getName() +
+ "' is not a 16 bit wide instruction!");
+ CodeGenInstruction DestInst(DestOperator);
+ verifyDagOpCount(DestInst, DestDag, false);
+
+ // Fill the mapping from the source to destination instructions.
+
+ IndexedMap<OpData> SourceOperandMap;
+ SourceOperandMap.grow(SourceInst.Operands.size());
+ // Create a mapping between source Dag operands and source Inst operands.
+ addDagOperandMapping(Rec, SourceDag, SourceInst, SourceOperandMap,
+ /*IsSourceInst*/ true);
+
+ IndexedMap<OpData> DestOperandMap;
+ DestOperandMap.grow(DestInst.Operands.size());
+ // Create a mapping between destination Dag operands and destination Inst
+ // operands.
+ addDagOperandMapping(Rec, DestDag, DestInst, DestOperandMap,
+ /*IsSourceInst*/ false);
+
+ StringMap<unsigned> SourceOperands;
+ StringMap<unsigned> DestOperands;
+ createDagOperandMapping(Rec, SourceOperands, DestOperands, SourceDag, DestDag,
+ SourceOperandMap);
+ // Create operand mapping between the source and destination instructions.
+ createInstOperandMapping(Rec, SourceDag, DestDag, SourceOperandMap,
+ DestOperandMap, SourceOperands, DestInst);
+
+ // Get the target features for the CompressPat.
+ std::vector<Record *> PatReqFeatures;
+ std::vector<Record *> RF = Rec->getValueAsListOfDefs("Predicates");
+ copy_if(RF, std::back_inserter(PatReqFeatures), [](Record *R) {
+ return R->getValueAsBit("AssemblerMatcherPredicate");
+ });
+
+ CompressPatterns.push_back(CompressPat(SourceInst, DestInst, PatReqFeatures,
+ SourceOperandMap, DestOperandMap));
+}
+
+static void getReqFeatures(std::map<StringRef, int> &FeaturesMap,
+ const std::vector<Record *> &ReqFeatures) {
+ for (auto &R : ReqFeatures) {
+ StringRef AsmCondString = R->getValueAsString("AssemblerCondString");
+
+ // AsmCondString has syntax [!]F(,[!]F)*
+ SmallVector<StringRef, 4> Ops;
+ SplitString(AsmCondString, Ops, ",");
+ assert(!Ops.empty() && "AssemblerCondString cannot be empty");
+
+ for (auto &Op : Ops) {
+ assert(!Op.empty() && "Empty operator");
+ if (FeaturesMap.find(Op) == FeaturesMap.end())
+ FeaturesMap[Op] = FeaturesMap.size();
+ }
+ }
+}
+
+unsigned getMCOpPredicate(DenseMap<const Record *, unsigned> &MCOpPredicateMap,
+ std::vector<const Record *> &MCOpPredicates,
+ Record *Rec) {
+ unsigned Entry = MCOpPredicateMap[Rec];
+ if (Entry)
+ return Entry;
+
+ if (!Rec->isValueUnset("MCOperandPredicate")) {
+ MCOpPredicates.push_back(Rec);
+ Entry = MCOpPredicates.size();
+ MCOpPredicateMap[Rec] = Entry;
+ return Entry;
+ }
+
+ PrintFatalError(Rec->getLoc(),
+ "No MCOperandPredicate on this operand at all: " +
+ Rec->getName().str() + "'");
+ return 0;
+}
+
+static std::string mergeCondAndCode(raw_string_ostream &CondStream,
+ raw_string_ostream &CodeStream) {
+ std::string S;
+ raw_string_ostream CombinedStream(S);
+ CombinedStream.indent(4)
+ << "if ("
+ << CondStream.str().substr(
+ 6, CondStream.str().length() -
+ 10) // remove first indentation and last '&&'.
+ << ") {\n";
+ CombinedStream << CodeStream.str();
+ CombinedStream.indent(4) << " return true;\n";
+ CombinedStream.indent(4) << "} // if\n";
+ return CombinedStream.str();
+}
+
+void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o,
+ bool Compress) {
+ Record *AsmWriter = Target.getAsmWriter();
+ if (!AsmWriter->getValueAsInt("PassSubtarget"))
+ PrintFatalError("'PassSubtarget' is false. SubTargetInfo object is needed "
+ "for target features.\n");
+
+ std::string Namespace = Target.getName();
+
+ // Sort entries in CompressPatterns to handle instructions that can have more
+ // than one candidate for compression\uncompression, e.g ADD can be
+ // transformed to a C_ADD or a C_MV. When emitting 'uncompress()' function the
+ // source and destination are flipped and the sort key needs to change
+ // accordingly.
+ std::stable_sort(CompressPatterns.begin(), CompressPatterns.end(),
+ [Compress](const CompressPat &LHS, const CompressPat &RHS) {
+ if (Compress)
+ return (LHS.Source.TheDef->getName().str() <
+ RHS.Source.TheDef->getName().str());
+ else
+ return (LHS.Dest.TheDef->getName().str() <
+ RHS.Dest.TheDef->getName().str());
+ });
+
+ // A list of MCOperandPredicates for all operands in use, and the reverse map.
+ std::vector<const Record *> MCOpPredicates;
+ DenseMap<const Record *, unsigned> MCOpPredicateMap;
+
+ std::string F;
+ std::string FH;
+ raw_string_ostream Func(F);
+ raw_string_ostream FuncH(FH);
+ bool NeedMRI = false;
+
+ if (Compress)
+ o << "\n#ifdef GEN_COMPRESS_INSTR\n"
+ << "#undef GEN_COMPRESS_INSTR\n\n";
+ else
+ o << "\n#ifdef GEN_UNCOMPRESS_INSTR\n"
+ << "#undef GEN_UNCOMPRESS_INSTR\n\n";
+
+ if (Compress) {
+ FuncH << "static bool compressInst(MCInst& OutInst,\n";
+ FuncH.indent(25) << "const MCInst &MI,\n";
+ FuncH.indent(25) << "const MCSubtargetInfo &STI,\n";
+ FuncH.indent(25) << "MCContext &Context) {\n";
+ } else {
+ FuncH << "static bool uncompressInst(MCInst& OutInst,\n";
+ FuncH.indent(27) << "const MCInst &MI,\n";
+ FuncH.indent(27) << "const MCRegisterInfo &MRI,\n";
+ FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n";
+ }
+
+ if (CompressPatterns.empty()) {
+ o << FuncH.str();
+ o.indent(2) << "return false;\n}\n";
+ if (Compress)
+ o << "\n#endif //GEN_COMPRESS_INSTR\n";
+ else
+ o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n";
+ return;
+ }
+
+ std::string CaseString("");
+ raw_string_ostream CaseStream(CaseString);
+ std::string PrevOp("");
+ std::string CurOp("");
+ CaseStream << " switch (MI.getOpcode()) {\n";
+ CaseStream << " default: return false;\n";
+
+ for (auto &CompressPat : CompressPatterns) {
+ std::string CondString;
+ std::string CodeString;
+ raw_string_ostream CondStream(CondString);
+ raw_string_ostream CodeStream(CodeString);
+ CodeGenInstruction &Source =
+ Compress ? CompressPat.Source : CompressPat.Dest;
+ CodeGenInstruction &Dest = Compress ? CompressPat.Dest : CompressPat.Source;
+ IndexedMap<OpData> SourceOperandMap =
+ Compress ? CompressPat.SourceOperandMap : CompressPat.DestOperandMap;
+ IndexedMap<OpData> &DestOperandMap =
+ Compress ? CompressPat.DestOperandMap : CompressPat.SourceOperandMap;
+
+ CurOp = Source.TheDef->getName().str();
+ // Check current and previous opcode to decide to continue or end a case.
+ if (CurOp != PrevOp) {
+ if (PrevOp != "")
+ CaseStream.indent(6) << "break;\n } // case " + PrevOp + "\n";
+ CaseStream.indent(4) << "case " + Namespace + "::" + CurOp + ": {\n";
+ }
+
+ std::map<StringRef, int> FeaturesMap;
+ // Add CompressPat required features.
+ getReqFeatures(FeaturesMap, CompressPat.PatReqFeatures);
+
+ // Add Dest instruction required features.
+ std::vector<Record *> ReqFeatures;
+ std::vector<Record *> RF = Dest.TheDef->getValueAsListOfDefs("Predicates");
+ copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) {
+ return R->getValueAsBit("AssemblerMatcherPredicate");
+ });
+ getReqFeatures(FeaturesMap, ReqFeatures);
+
+ // Emit checks for all required features.
+ for (auto &F : FeaturesMap) {
+ StringRef Op = F.first;
+ if (Op[0] == '!')
+ CondStream.indent(6) << ("!STI.getFeatureBits()[" + Namespace +
+ "::" + Op.substr(1) + "]")
+ .str() +
+ " &&\n";
+ else
+ CondStream.indent(6)
+ << ("STI.getFeatureBits()[" + Namespace + "::" + Op + "]").str() +
+ " &&\n";
+ }
+
+ // Start Source Inst operands validation.
+ unsigned OpNo = 0;
+ for (OpNo = 0; OpNo < Source.Operands.size(); ++OpNo) {
+ if (SourceOperandMap[OpNo].TiedOpIdx != -1) {
+ if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass"))
+ CondStream.indent(6)
+ << "(MI.getOperand("
+ << std::to_string(OpNo) + ").getReg() == MI.getOperand("
+ << std::to_string(SourceOperandMap[OpNo].TiedOpIdx)
+ << ").getReg()) &&\n";
+ else
+ PrintFatalError("Unexpected tied operand types!\n");
+ }
+ // Check for fixed immediates\registers in the source instruction.
+ switch (SourceOperandMap[OpNo].Kind) {
+ case OpData::Operand:
+ // We don't need to do anything for source instruction operand checks.
+ break;
+ case OpData::Imm:
+ CondStream.indent(6)
+ << "(MI.getOperand(" + std::to_string(OpNo) + ").isImm()) &&\n" +
+ " (MI.getOperand(" + std::to_string(OpNo) +
+ ").getImm() == " +
+ std::to_string(SourceOperandMap[OpNo].Data.Imm) + ") &&\n";
+ break;
+ case OpData::Reg: {
+ Record *Reg = SourceOperandMap[OpNo].Data.Reg;
+ CondStream.indent(6) << "(MI.getOperand(" + std::to_string(OpNo) +
+ ").getReg() == " + Namespace +
+ "::" + Reg->getName().str() + ") &&\n";
+ break;
+ }
+ }
+ }
+ CodeStream.indent(6) << "// " + Dest.AsmString + "\n";
+ CodeStream.indent(6) << "OutInst.setOpcode(" + Namespace +
+ "::" + Dest.TheDef->getName().str() + ");\n";
+ OpNo = 0;
+ for (const auto &DestOperand : Dest.Operands) {
+ CodeStream.indent(6) << "// Operand: " + DestOperand.Name + "\n";
+ switch (DestOperandMap[OpNo].Kind) {
+ case OpData::Operand: {
+ unsigned OpIdx = DestOperandMap[OpNo].Data.Operand;
+ // Check that the operand in the Source instruction fits
+ // the type for the Dest instruction.
+ if (DestOperand.Rec->isSubClassOf("RegisterClass")) {
+ NeedMRI = true;
+ // This is a register operand. Check the register class.
+ // Don't check register class if this is a tied operand, it was done
+ // for the operand its tied to.
+ if (DestOperand.getTiedRegister() == -1)
+ CondStream.indent(6)
+ << "(MRI.getRegClass(" + Namespace +
+ "::" + DestOperand.Rec->getName().str() +
+ "RegClassID).contains(" + "MI.getOperand(" +
+ std::to_string(OpIdx) + ").getReg())) &&\n";
+
+ CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" +
+ std::to_string(OpIdx) + "));\n";
+ } else {
+ // Handling immediate operands.
+ unsigned Entry = getMCOpPredicate(MCOpPredicateMap, MCOpPredicates,
+ DestOperand.Rec);
+ CondStream.indent(6) << Namespace + "ValidateMCOperand(" +
+ "MI.getOperand(" + std::to_string(OpIdx) +
+ "), STI, " + std::to_string(Entry) +
+ ") &&\n";
+ CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" +
+ std::to_string(OpIdx) + "));\n";
+ }
+ break;
+ }
+ case OpData::Imm: {
+ unsigned Entry =
+ getMCOpPredicate(MCOpPredicateMap, MCOpPredicates, DestOperand.Rec);
+ CondStream.indent(6)
+ << Namespace + "ValidateMCOperand(" + "MCOperand::createImm(" +
+ std::to_string(DestOperandMap[OpNo].Data.Imm) + "), STI, " +
+ std::to_string(Entry) + ") &&\n";
+ CodeStream.indent(6)
+ << "OutInst.addOperand(MCOperand::createImm(" +
+ std::to_string(DestOperandMap[OpNo].Data.Imm) + "));\n";
+ } break;
+ case OpData::Reg: {
+ // Fixed register has been validated at pattern validation time.
+ Record *Reg = DestOperandMap[OpNo].Data.Reg;
+ CodeStream.indent(6) << "OutInst.addOperand(MCOperand::createReg(" +
+ Namespace + "::" + Reg->getName().str() +
+ "));\n";
+ } break;
+ }
+ ++OpNo;
+ }
+ CaseStream << mergeCondAndCode(CondStream, CodeStream);
+ PrevOp = CurOp;
+ }
+ Func << CaseStream.str() << "\n";
+ // Close brace for the last case.
+ Func.indent(4) << "} // case " + CurOp + "\n";
+ Func.indent(2) << "} // switch\n";
+ Func.indent(2) << "return false;\n}\n";
+
+ if (!MCOpPredicates.empty()) {
+ o << "static bool " << Namespace
+ << "ValidateMCOperand(const MCOperand &MCOp,\n"
+ << " const MCSubtargetInfo &STI,\n"
+ << " unsigned PredicateIndex) {\n"
+ << " switch (PredicateIndex) {\n"
+ << " default:\n"
+ << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n"
+ << " break;\n";
+
+ for (unsigned i = 0; i < MCOpPredicates.size(); ++i) {
+ Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate");
+ if (CodeInit *SI = dyn_cast<CodeInit>(MCOpPred))
+ o << " case " << i + 1 << ": {\n"
+ << " // " << MCOpPredicates[i]->getName().str() << SI->getValue()
+ << "\n"
+ << " }\n";
+ else
+ llvm_unreachable("Unexpected MCOperandPredicate field!");
+ }
+ o << " }\n"
+ << "}\n\n";
+ }
+
+ o << FuncH.str();
+ if (NeedMRI && Compress)
+ o.indent(2) << "const MCRegisterInfo &MRI = *Context.getRegisterInfo();\n";
+ o << Func.str();
+
+ if (Compress)
+ o << "\n#endif //GEN_COMPRESS_INSTR\n";
+ else
+ o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n";
+}
+
+void RISCVCompressInstEmitter::run(raw_ostream &o) {
+ Record *CompressClass = Records.getClass("CompressPat");
+ assert(CompressClass && "Compress class definition missing!");
+ std::vector<Record *> Insts;
+ for (const auto &D : Records.getDefs()) {
+ if (D.second->isSubClassOf(CompressClass))
+ Insts.push_back(D.second.get());
+ }
+
+ // Process the CompressPat definitions, validating them as we do so.
+ for (unsigned i = 0, e = Insts.size(); i != e; ++i)
+ evaluateCompressPat(Insts[i]);
+
+ // Emit file header.
+ emitSourceFileHeader("Compress instruction Source Fragment", o);
+ // Generate compressInst() function.
+ emitCompressInstEmitter(o, true);
+ // Generate uncompressInst() function.
+ emitCompressInstEmitter(o, false);
+}
+
+namespace llvm {
+
+void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS) {
+ RISCVCompressInstEmitter(RK).run(OS);
+}
+
+} // namespace llvm
diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp
index b0e0385a45c..cf0b0c24f83 100644
--- a/llvm/utils/TableGen/TableGen.cpp
+++ b/llvm/utils/TableGen/TableGen.cpp
@@ -32,6 +32,7 @@ enum ActionType {
GenAsmMatcher,
GenDisassembler,
GenPseudoLowering,
+ GenCompressInst,
GenCallingConv,
GenDAGISel,
GenDFAPacketizer,
@@ -72,6 +73,8 @@ namespace {
"Generate disassembler"),
clEnumValN(GenPseudoLowering, "gen-pseudo-lowering",
"Generate pseudo instruction lowering"),
+ clEnumValN(GenCompressInst, "gen-compress-inst-emitter",
+ "Generate RISCV compressed instructions."),
clEnumValN(GenAsmMatcher, "gen-asm-matcher",
"Generate assembly instruction matcher"),
clEnumValN(GenDAGISel, "gen-dag-isel",
@@ -144,6 +147,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenPseudoLowering:
EmitPseudoLowering(Records, OS);
break;
+ case GenCompressInst:
+ EmitCompressInst(Records, OS);
+ break;
case GenDAGISel:
EmitDAGISel(Records, OS);
break;
diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h
index 914cd5a1fc9..09f74aa017f 100644
--- a/llvm/utils/TableGen/TableGenBackends.h
+++ b/llvm/utils/TableGen/TableGenBackends.h
@@ -74,6 +74,7 @@ void EmitFastISel(RecordKeeper &RK, raw_ostream &OS);
void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS);
void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS);
void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS);
+void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS);
void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS);
void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS);
void EmitMapTable(RecordKeeper &RK, raw_ostream &OS);
OpenPOWER on IntegriCloud