[llvm] r329455 - [RISCV] Tablegen-driven Instruction Compression.

Sameer AbuAsal via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 6 14:07:05 PDT 2018


Author: sabuasal
Date: Fri Apr  6 14:07:05 2018
New Revision: 329455

URL: http://llvm.org/viewvc/llvm-project?rev=329455&view=rev
Log:
    [RISCV] Tablegen-driven Instruction Compression.

Summary:

    This patch implements a tablegen-driven Instruction Compression
    mechanism for generating RISCV compressed instructions
    (C Extension) from the expanded instruction form.

    This tablegen backend processes CompressPat declarations in a
    td file and generates all the compile-time and runtime checks
    required to validate the declarations, validate the input
    operands and generate correct instructions.

    The checks include validating register operands, immediate
    operands, fixed register operands and fixed immediate operands.

    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
    'RISCVGenCompressEmitter.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.

    The following clients were added to implement compression\uncompression
    for RISCV:

    1) RISCVAsmParser::MatchAndEmitInstruction:
       Inserted a call to compressInst() to compresses instructions
       parsed by llvm-mc coming from an ASM input.
    2) RISCVAsmPrinter::EmitInstruction:
       Inserted a call to compressInst() to compress instructions that
       were lowered from Machine Instructions (MachineInstr).
    3) RVInstPrinter::printInst:
       Inserted a call to uncompressInst() to print the expanded
       version of the instruction instead of the compressed one (e.g,
       add s0, s0, a5 instead of c.add s0, a5) when -riscv-no-aliases
       is not passed.

This patch squashes D45119, D42780 and D41932. It was reviewed in  smaller patches by
asb, efriedma, apazos and mgrang.

Reviewers: asb, efriedma, apazos, llvm-commits, sabuasal

Reviewed By: sabuasal

Subscribers: mgorny, eraman, asb, rbar, johnrusso, simoncook, jordy.potman.lists, apazos, niosHD, kito-cheng, shiva0217, zzheng

Differential Revision: https://reviews.llvm.org/D45385

Added:
    llvm/trunk/test/CodeGen/RISCV/compress-Pseudo.ll
    llvm/trunk/test/CodeGen/RISCV/compress-inline-asm.ll
    llvm/trunk/test/MC/RISCV/compress-cjal.s
    llvm/trunk/test/MC/RISCV/compress-rv32d.s
    llvm/trunk/test/MC/RISCV/compress-rv32f.s
    llvm/trunk/test/MC/RISCV/compress-rv32i.s
    llvm/trunk/test/MC/RISCV/compress-rv64i.s
    llvm/trunk/test/MC/RISCV/compressed-relocations.s
    llvm/trunk/utils/TableGen/RISCVCompressInstEmitter.cpp
Modified:
    llvm/trunk/include/llvm/MC/MCInst.h
    llvm/trunk/lib/MC/MCInst.cpp
    llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
    llvm/trunk/lib/Target/RISCV/CMakeLists.txt
    llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
    llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
    llvm/trunk/lib/Target/RISCV/RISCVAsmPrinter.cpp
    llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td
    llvm/trunk/lib/Target/RISCV/RISCVInstrInfoC.td
    llvm/trunk/test/CodeGen/RISCV/alu32.ll
    llvm/trunk/test/CodeGen/RISCV/branch.ll
    llvm/trunk/test/MC/RISCV/cnop.s
    llvm/trunk/test/MC/RISCV/fixups-compressed.s
    llvm/trunk/test/MC/RISCV/relocations.s
    llvm/trunk/test/MC/RISCV/rv32-relaxation.s
    llvm/trunk/test/MC/RISCV/rv64-relaxation.s
    llvm/trunk/utils/TableGen/CMakeLists.txt
    llvm/trunk/utils/TableGen/TableGen.cpp
    llvm/trunk/utils/TableGen/TableGenBackends.h

Modified: llvm/trunk/include/llvm/MC/MCInst.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCInst.h?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCInst.h (original)
+++ llvm/trunk/include/llvm/MC/MCInst.h Fri Apr  6 14:07:05 2018
@@ -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; };

Modified: llvm/trunk/lib/MC/MCInst.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCInst.cpp?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCInst.cpp (original)
+++ llvm/trunk/lib/MC/MCInst.cpp Fri Apr  6 14:07:05 2018
@@ -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) c
   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());

Modified: llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp Fri Apr  6 14:07:05 2018
@@ -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::MatchAndEmitInstruc
   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:

Modified: llvm/trunk/lib/Target/RISCV/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/CMakeLists.txt?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/CMakeLists.txt (original)
+++ llvm/trunk/lib/Target/RISCV/CMakeLists.txt Fri Apr  6 14:07:05 2018
@@ -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)

Modified: llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/InstPrinter/RISCVInstPrinter.cpp Fri Apr  6 14:07:05 2018
@@ -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);
 }
 

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp Fri Apr  6 14:07:05 2018
@@ -12,6 +12,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "RISCV.h"
 #include "RISCVMCExpr.h"
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCContext.h"

Modified: llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h (original)
+++ llvm/trunk/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h Fri Apr  6 14:07:05 2018
@@ -20,6 +20,7 @@
 namespace llvm {
 
 class StringRef;
+class MCOperand;
 class RISCVMCExpr : public MCTargetExpr {
 public:
   enum VariantKind {

Modified: llvm/trunk/lib/Target/RISCV/RISCVAsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVAsmPrinter.cpp?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVAsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVAsmPrinter.cpp Fri Apr  6 14:07:05 2018
@@ -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"

Modified: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td Fri Apr  6 14:07:05 2018
@@ -83,6 +83,14 @@ def uimmlog2xlen : Operand<XLenVT>, ImmL
   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<XL
   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.

Modified: llvm/trunk/lib/Target/RISCV/RISCVInstrInfoC.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVInstrInfoC.td?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVInstrInfoC.td (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfoC.td Fri Apr  6 14:07:05 2018
@@ -27,12 +27,26 @@ def uimmlog2xlennonzero : Operand<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<XLen
   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"
 }
 
 } // 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]

Modified: llvm/trunk/test/CodeGen/RISCV/alu32.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/alu32.ll?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/alu32.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/alu32.ll Fri Apr  6 14:07:05 2018
@@ -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
 }

Modified: llvm/trunk/test/CodeGen/RISCV/branch.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/branch.ll?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/branch.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/branch.ll Fri Apr  6 14:07:05 2018
@@ -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

Added: llvm/trunk/test/CodeGen/RISCV/compress-Pseudo.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/compress-Pseudo.ll?rev=329455&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/compress-Pseudo.ll (added)
+++ llvm/trunk/test/CodeGen/RISCV/compress-Pseudo.ll Fri Apr  6 14:07:05 2018
@@ -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
+}

Added: llvm/trunk/test/CodeGen/RISCV/compress-inline-asm.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/compress-inline-asm.ll?rev=329455&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/compress-inline-asm.ll (added)
+++ llvm/trunk/test/CodeGen/RISCV/compress-inline-asm.ll Fri Apr  6 14:07:05 2018
@@ -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
+
+ at 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
+}
+

Modified: llvm/trunk/test/MC/RISCV/cnop.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/cnop.s?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/test/MC/RISCV/cnop.s (original)
+++ llvm/trunk/test/MC/RISCV/cnop.s Fri Apr  6 14:07:05 2018
@@ -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

Added: llvm/trunk/test/MC/RISCV/compress-cjal.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/compress-cjal.s?rev=329455&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/compress-cjal.s (added)
+++ llvm/trunk/test/MC/RISCV/compress-cjal.s Fri Apr  6 14:07:05 2018
@@ -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]

Added: llvm/trunk/test/MC/RISCV/compress-rv32d.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/compress-rv32d.s?rev=329455&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/compress-rv32d.s (added)
+++ llvm/trunk/test/MC/RISCV/compress-rv32d.s Fri Apr  6 14:07:05 2018
@@ -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]

Added: llvm/trunk/test/MC/RISCV/compress-rv32f.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/compress-rv32f.s?rev=329455&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/compress-rv32f.s (added)
+++ llvm/trunk/test/MC/RISCV/compress-rv32f.s Fri Apr  6 14:07:05 2018
@@ -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]

Added: llvm/trunk/test/MC/RISCV/compress-rv32i.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/compress-rv32i.s?rev=329455&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/compress-rv32i.s (added)
+++ llvm/trunk/test/MC/RISCV/compress-rv32i.s Fri Apr  6 14:07:05 2018
@@ -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)

Added: llvm/trunk/test/MC/RISCV/compress-rv64i.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/compress-rv64i.s?rev=329455&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/compress-rv64i.s (added)
+++ llvm/trunk/test/MC/RISCV/compress-rv64i.s Fri Apr  6 14:07:05 2018
@@ -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)

Added: llvm/trunk/test/MC/RISCV/compressed-relocations.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/compressed-relocations.s?rev=329455&view=auto
==============================================================================
--- llvm/trunk/test/MC/RISCV/compressed-relocations.s (added)
+++ llvm/trunk/test/MC/RISCV/compressed-relocations.s Fri Apr  6 14:07:05 2018
@@ -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

Modified: llvm/trunk/test/MC/RISCV/fixups-compressed.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/fixups-compressed.s?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/test/MC/RISCV/fixups-compressed.s (original)
+++ llvm/trunk/test/MC/RISCV/fixups-compressed.s Fri Apr  6 14:07:05 2018
@@ -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
 

Modified: llvm/trunk/test/MC/RISCV/relocations.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/relocations.s?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/test/MC/RISCV/relocations.s (original)
+++ llvm/trunk/test/MC/RISCV/relocations.s Fri Apr  6 14:07:05 2018
@@ -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

Modified: llvm/trunk/test/MC/RISCV/rv32-relaxation.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/rv32-relaxation.s?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/test/MC/RISCV/rv32-relaxation.s (original)
+++ llvm/trunk/test/MC/RISCV/rv32-relaxation.s Fri Apr  6 14:07:05 2018
@@ -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

Modified: llvm/trunk/test/MC/RISCV/rv64-relaxation.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/rv64-relaxation.s?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/test/MC/RISCV/rv64-relaxation.s (original)
+++ llvm/trunk/test/MC/RISCV/rv64-relaxation.s Fri Apr  6 14:07:05 2018
@@ -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

Modified: llvm/trunk/utils/TableGen/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CMakeLists.txt?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/CMakeLists.txt (original)
+++ llvm/trunk/utils/TableGen/CMakeLists.txt Fri Apr  6 14:07:05 2018
@@ -30,6 +30,7 @@ add_tablegen(llvm-tblgen LLVM
   IntrinsicEmitter.cpp
   OptParserEmitter.cpp
   PseudoLoweringEmitter.cpp
+  RISCVCompressInstEmitter.cpp
   RegisterBankEmitter.cpp
   RegisterInfoEmitter.cpp
   SDNodeProperties.cpp

Added: llvm/trunk/utils/TableGen/RISCVCompressInstEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/RISCVCompressInstEmitter.cpp?rev=329455&view=auto
==============================================================================
--- llvm/trunk/utils/TableGen/RISCVCompressInstEmitter.cpp (added)
+++ llvm/trunk/utils/TableGen/RISCVCompressInstEmitter.cpp Fri Apr  6 14:07:05 2018
@@ -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

Modified: llvm/trunk/utils/TableGen/TableGen.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/TableGen.cpp?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/TableGen.cpp (original)
+++ llvm/trunk/utils/TableGen/TableGen.cpp Fri Apr  6 14:07:05 2018
@@ -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, R
   case GenPseudoLowering:
     EmitPseudoLowering(Records, OS);
     break;
+  case GenCompressInst:
+    EmitCompressInst(Records, OS);
+    break;
   case GenDAGISel:
     EmitDAGISel(Records, OS);
     break;

Modified: llvm/trunk/utils/TableGen/TableGenBackends.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/TableGenBackends.h?rev=329455&r1=329454&r2=329455&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/TableGenBackends.h (original)
+++ llvm/trunk/utils/TableGen/TableGenBackends.h Fri Apr  6 14:07:05 2018
@@ -74,6 +74,7 @@ void EmitFastISel(RecordKeeper &RK, raw_
 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);




More information about the llvm-commits mailing list