]> granicus.if.org Git - llvm/commitdiff
[RISCV] Add support for RVC HINT instructions
authorLuis Marques <luismarques@lowrisc.org>
Wed, 21 Aug 2019 14:00:58 +0000 (14:00 +0000)
committerLuis Marques <luismarques@lowrisc.org>
Wed, 21 Aug 2019 14:00:58 +0000 (14:00 +0000)
The hint instructions are enabled by default (if the standard C extension is
enabled). To disable them pass -mattr=-rvc-hints.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@369528 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
lib/Target/RISCV/RISCV.td
lib/Target/RISCV/RISCVInstrInfo.td
lib/Target/RISCV/RISCVInstrInfoC.td
lib/Target/RISCV/RISCVRegisterInfo.td
lib/Target/RISCV/RISCVSubtarget.h
test/MC/RISCV/rv32c-invalid.s
test/MC/RISCV/rv64c-hints-valid.s [new file with mode: 0644]
test/MC/RISCV/rvc-hints-invalid.s [new file with mode: 0644]
test/MC/RISCV/rvc-hints-valid.s [new file with mode: 0644]

index 55ce2e4e16aa7faaf0853f99d2b3a658328b894a..9605444080ce02a1a89aa28a42575cf39746999d 100644 (file)
@@ -864,6 +864,10 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     return generateImmOutOfRangeError(Operands, ErrorInfo,
                                       std::numeric_limits<int32_t>::min(),
                                       std::numeric_limits<uint32_t>::max());
+  case Match_InvalidImmZero: {
+    SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+    return Error(ErrorLoc, "immediate must be zero");
+  }
   case Match_InvalidUImmLog2XLen:
     if (isRV64())
       return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 6) - 1);
index 9ca3a31d60b07501b5d9fb2e54eb9ccfb36421d2..f120800bdbe25c486ec9334fab84a514afb5d620 100644 (file)
@@ -280,8 +280,77 @@ static DecodeStatus decodeFRMArg(MCInst &Inst, uint64_t Imm,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeRVCInstrSImm(MCInst &Inst, unsigned Insn,
+                                       uint64_t Address, const void *Decoder);
+
+static DecodeStatus decodeRVCInstrRdSImm(MCInst &Inst, unsigned Insn,
+                                         uint64_t Address, const void *Decoder);
+
+static DecodeStatus decodeRVCInstrRdRs1UImm(MCInst &Inst, unsigned Insn,
+                                            uint64_t Address,
+                                            const void *Decoder);
+
+static DecodeStatus decodeRVCInstrRdRs2(MCInst &Inst, unsigned Insn,
+                                        uint64_t Address, const void *Decoder);
+
+static DecodeStatus decodeRVCInstrRdRs1Rs2(MCInst &Inst, unsigned Insn,
+                                           uint64_t Address,
+                                           const void *Decoder);
+
 #include "RISCVGenDisassemblerTables.inc"
 
+static DecodeStatus decodeRVCInstrSImm(MCInst &Inst, unsigned Insn,
+                                       uint64_t Address, const void *Decoder) {
+  uint64_t SImm6 =
+      fieldFromInstruction(Insn, 12, 1) << 5 | fieldFromInstruction(Insn, 2, 5);
+  assert(decodeSImmOperand<6>(Inst, SImm6, Address, Decoder) ==
+      MCDisassembler::Success && "Invalid immediate");
+  return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeRVCInstrRdSImm(MCInst &Inst, unsigned Insn,
+                                         uint64_t Address,
+                                         const void *Decoder) {
+  DecodeGPRRegisterClass(Inst, 0, Address, Decoder);
+  uint64_t SImm6 =
+      fieldFromInstruction(Insn, 12, 1) << 5 | fieldFromInstruction(Insn, 2, 5);
+  assert(decodeSImmOperand<6>(Inst, SImm6, Address, Decoder) ==
+      MCDisassembler::Success && "Invalid immediate");
+  return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeRVCInstrRdRs1UImm(MCInst &Inst, unsigned Insn,
+                                            uint64_t Address,
+                                            const void *Decoder) {
+  DecodeGPRRegisterClass(Inst, 0, Address, Decoder);
+  Inst.addOperand(Inst.getOperand(0));
+  uint64_t UImm6 =
+      fieldFromInstruction(Insn, 12, 1) << 5 | fieldFromInstruction(Insn, 2, 5);
+  assert(decodeUImmOperand<6>(Inst, UImm6, Address, Decoder) ==
+      MCDisassembler::Success && "Invalid immediate");
+  return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeRVCInstrRdRs2(MCInst &Inst, unsigned Insn,
+                                        uint64_t Address, const void *Decoder) {
+  unsigned Rd = fieldFromInstruction(Insn, 7, 5);
+  unsigned Rs2 = fieldFromInstruction(Insn, 2, 5);
+  DecodeGPRRegisterClass(Inst, Rd, Address, Decoder);
+  DecodeGPRRegisterClass(Inst, Rs2, Address, Decoder);
+  return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeRVCInstrRdRs1Rs2(MCInst &Inst, unsigned Insn,
+                                           uint64_t Address,
+                                           const void *Decoder) {
+  unsigned Rd = fieldFromInstruction(Insn, 7, 5);
+  unsigned Rs2 = fieldFromInstruction(Insn, 2, 5);
+  DecodeGPRRegisterClass(Inst, Rd, Address, Decoder);
+  Inst.addOperand(Inst.getOperand(0));
+  DecodeGPRRegisterClass(Inst, Rs2, Address, Decoder);
+  return MCDisassembler::Success;
+}
+
 DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
                                                ArrayRef<uint8_t> Bytes,
                                                uint64_t Address,
index a4775dca7e095fda3f9087d5fcb7af0f6bc9376c..46530a8f74a883359e5c2e0885107b4697bcb99e 100644 (file)
@@ -43,6 +43,11 @@ def FeatureStdExtC
 def HasStdExtC : Predicate<"Subtarget->hasStdExtC()">,
                            AssemblerPredicate<"FeatureStdExtC">;
 
+def FeatureRVCHints
+    : SubtargetFeature<"rvc-hints", "EnableRVCHintInstrs", "true",
+                       "Enable RVC Hint Instructions.">;
+def HasRVCHints : Predicate<"Subtarget->enableRVCHintInstrs()">,
+                            AssemblerPredicate<"FeatureRVCHints">;
 
 def Feature64Bit
     : SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">;
@@ -83,9 +88,10 @@ include "RISCVRegisterBanks.td"
 // RISC-V processors supported.
 //===----------------------------------------------------------------------===//
 
-def : ProcessorModel<"generic-rv32", NoSchedModel, []>;
+def : ProcessorModel<"generic-rv32", NoSchedModel, [FeatureRVCHints]>;
 
-def : ProcessorModel<"generic-rv64", NoSchedModel, [Feature64Bit]>;
+def : ProcessorModel<"generic-rv64", NoSchedModel, [Feature64Bit,
+                     FeatureRVCHints]>;
 
 //===----------------------------------------------------------------------===//
 // Define the RISC-V target.
index 69bde15f1218765cb3842f4ebd1eaed8a64ac1cb..fd130d12d97b67d37e4bb58e0cf47613d692935f 100644 (file)
@@ -69,6 +69,12 @@ class ImmAsmOperand<string prefix, int width, string suffix> : AsmOperandClass {
   let DiagnosticType = !strconcat("Invalid", Name);
 }
 
+def ImmZeroAsmOperand : AsmOperandClass {
+  let Name = "ImmZero";
+  let RenderMethod = "addImmOperands";
+  let DiagnosticType = !strconcat("Invalid", Name);
+}
+
 class SImmAsmOperand<int width, string suffix = "">
     : ImmAsmOperand<"S", width, suffix> {
 }
index 94477341eea7451de7248bb14d832dc5f1d4fbe2..a8809a8fbad6b7e46ebd98ad54582aa703db4275 100644 (file)
@@ -61,6 +61,11 @@ def simm6nonzero : Operand<XLenVT>,
   }];
 }
 
+def immzero : Operand<XLenVT>,
+              ImmLeaf<XLenVT, [{return (Imm == 0);}]> {
+  let ParserMatchClass = ImmZeroAsmOperand;
+}
+
 def CLUIImmAsmOperand : AsmOperandClass {
   let Name = "CLUIImm";
   let RenderMethod = "addImmOperands";
@@ -344,7 +349,10 @@ def C_SD : CStore_rri<0b111, "c.sd", GPRC, uimm8_lsb000> {
 }
 
 let rd = 0, imm = 0, hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
-def C_NOP : RVInst16CI<0b000, 0b01, (outs), (ins), "c.nop", "">;
+def C_NOP : RVInst16CI<0b000, 0b01, (outs), (ins), "c.nop", "">
+{
+  let Inst{6-2} = 0;
+}
 
 let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
 def C_ADDI : RVInst16CI<0b000, 0b01, (outs GPRNoX0:$rd_wb),
@@ -354,6 +362,15 @@ def C_ADDI : RVInst16CI<0b000, 0b01, (outs GPRNoX0:$rd_wb),
   let Inst{6-2} = imm{4-0};
 }
 
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
+def C_ADDI_NOP : RVInst16CI<0b000, 0b01, (outs GPRX0:$rd_wb),
+                            (ins GPRX0:$rd, immzero:$imm),
+                            "c.addi", "$rd, $imm"> {
+  let Constraints = "$rd = $rd_wb";
+  let Inst{6-2} = 0;
+  let isAsmParserOnly = 1;
+}
+
 let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCall = 1,
     DecoderNamespace = "RISCV32Only_", Defs = [X1],
     Predicates = [HasStdExtC, IsRV32]  in
@@ -522,6 +539,105 @@ def C_UNIMP : RVInst16<(outs), (ins), "c.unimp", "", [], InstFormatOther> {
 
 } // Predicates = [HasStdExtC]
 
+//===----------------------------------------------------------------------===//
+// HINT Instructions
+//===----------------------------------------------------------------------===//
+
+let Predicates = [HasStdExtC, HasRVCHints], hasSideEffects = 0, mayLoad = 0,
+    mayStore = 0 in
+{
+
+let rd = 0 in
+def C_NOP_HINT : RVInst16CI<0b000, 0b01, (outs), (ins simm6nonzero:$imm),
+                            "c.nop", "$imm"> {
+  let Inst{6-2} = imm{4-0};
+  let DecoderMethod = "decodeRVCInstrSImm";
+}
+
+// Just a different syntax for the c.nop hint: c.addi x0, simm6 vs c.nop simm6.
+def C_ADDI_HINT_X0 : RVInst16CI<0b000, 0b01, (outs GPRX0:$rd_wb),
+                                (ins GPRX0:$rd, simm6nonzero:$imm),
+                                "c.addi", "$rd, $imm"> {
+  let Constraints = "$rd = $rd_wb";
+  let Inst{6-2} = imm{4-0};
+  let isAsmParserOnly = 1;
+}
+
+def C_ADDI_HINT_IMM_ZERO : RVInst16CI<0b000, 0b01, (outs GPRNoX0:$rd_wb),
+                                      (ins GPRNoX0:$rd, immzero:$imm),
+                                      "c.addi", "$rd, $imm"> {
+  let Constraints = "$rd = $rd_wb";
+  let Inst{6-2} = 0;
+  let isAsmParserOnly = 1;
+}
+
+def C_LI_HINT : RVInst16CI<0b010, 0b01, (outs GPRX0:$rd), (ins simm6:$imm),
+                           "c.li", "$rd, $imm"> {
+  let Inst{6-2} = imm{4-0};
+  let Inst{11-7} = 0;
+  let DecoderMethod = "decodeRVCInstrRdSImm";
+}
+
+def C_LUI_HINT : RVInst16CI<0b011, 0b01, (outs GPRX0:$rd),
+                            (ins c_lui_imm:$imm),
+                            "c.lui", "$rd, $imm"> {
+  let Inst{6-2} = imm{4-0};
+  let Inst{11-7} = 0;
+  let DecoderMethod = "decodeRVCInstrRdSImm";
+}
+
+def C_MV_HINT : RVInst16CR<0b1000, 0b10, (outs GPRX0:$rs1), (ins GPRNoX0:$rs2),
+                           "c.mv", "$rs1, $rs2">
+{
+  let Inst{11-7} = 0;
+  let DecoderMethod = "decodeRVCInstrRdRs2";
+}
+
+def C_ADD_HINT : RVInst16CR<0b1001, 0b10, (outs GPRX0:$rs1_wb),
+                            (ins GPRX0:$rs1, GPRNoX0:$rs2),
+                            "c.add", "$rs1, $rs2"> {
+  let Constraints = "$rs1 = $rs1_wb";
+  let Inst{11-7} = 0;
+  let DecoderMethod = "decodeRVCInstrRdRs1Rs2";
+}
+
+def C_SLLI_HINT : RVInst16CI<0b000, 0b10, (outs GPRX0:$rd_wb),
+                             (ins GPRX0:$rd, uimmlog2xlennonzero:$imm),
+                             "c.slli" ,"$rd, $imm"> {
+  let Constraints = "$rd = $rd_wb";
+  let Inst{6-2} = imm{4-0};
+  let Inst{11-7} = 0;
+  let DecoderMethod = "decodeRVCInstrRdRs1UImm";
+}
+
+def C_SLLI64_HINT : RVInst16CI<0b000, 0b10, (outs GPR:$rd_wb), (ins GPR:$rd),
+                               "c.slli64" ,"$rd"> {
+  let Constraints = "$rd = $rd_wb";
+  let Inst{6-2} = 0;
+  let Inst{12} = 0;
+}
+
+def C_SRLI64_HINT : RVInst16CI<0b100, 0b01, (outs GPRC:$rd_wb),
+                               (ins GPRC:$rd),
+                               "c.srli64", "$rd"> {
+  let Constraints = "$rd = $rd_wb";
+  let Inst{6-2} = 0;
+  let Inst{11-10} = 0;
+  let Inst{12} = 0;
+}
+
+def C_SRAI64_HINT : RVInst16CI<0b100, 0b01, (outs GPRC:$rd_wb),
+                               (ins GPRC:$rd),
+                               "c.srai64", "$rd"> {
+  let Constraints = "$rd = $rd_wb";
+  let Inst{6-2} = 0;
+  let Inst{11-10} = 1;
+  let Inst{12} = 0;
+}
+
+} // Predicates = [HasStdExtC, HasRVCHints], hasSideEffects = 0, mayLoad = 0,
+  // mayStore = 0
+
 //===----------------------------------------------------------------------===//
 // Assembler Pseudo Instructions
 //===----------------------------------------------------------------------===//
index 79f8ab12f6c0a74e05f64b8cbd3749629212088c..9b039212b4d6fbb5449e20d52bc67054afd5eb33 100644 (file)
@@ -101,6 +101,12 @@ def GPR : RegisterClass<"RISCV", [XLenVT], 32, (add
       [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>;
 }
 
+def GPRX0 : RegisterClass<"RISCV", [XLenVT], 32, (add X0)> {
+  let RegInfos = RegInfoByHwMode<
+      [RV32,              RV64,              DefaultMode],
+      [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>;
+}
+
 // The order of registers represents the preferred allocation sequence.
 // Registers are listed in the order caller-save, callee-save, specials.
 def GPRNoX0 : RegisterClass<"RISCV", [XLenVT], 32, (add
index 12ba5f844b0691d5062960cbf447d5e3c4528b9a..fa19252f1f15fea706ece71bdd709573b5f588ce 100644 (file)
@@ -42,6 +42,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
   bool HasRV64 = false;
   bool IsRV32E = false;
   bool EnableLinkerRelax = false;
+  bool EnableRVCHintInstrs = false;
   unsigned XLen = 32;
   MVT XLenVT = MVT::i32;
   RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown;
@@ -87,6 +88,7 @@ public:
   bool is64Bit() const { return HasRV64; }
   bool isRV32E() const { return IsRV32E; }
   bool enableLinkerRelax() const { return EnableLinkerRelax; }
+  bool enableRVCHintInstrs() const { return EnableRVCHintInstrs; }
   MVT getXLenVT() const { return XLenVT; }
   unsigned getXLen() const { return XLen; }
   RISCVABI::ABI getTargetABI() const { return TargetABI; }
index 9981f67b5e14e9fcc4641c36f6194c090ee9ce3a..1ebd25250081b10f89167def1f5b96dc9f0a64d9 100644 (file)
@@ -1,4 +1,5 @@
-# RUN: not llvm-mc -triple=riscv32 -mattr=+c < %s 2>&1 | FileCheck %s
+# RUN: not llvm-mc -triple=riscv32 -mattr=+c -mattr=-rvc-hints < %s 2>&1 \
+# RUN:     | FileCheck %s
 
 ## GPRC
 .LBB:
@@ -20,16 +21,16 @@ c.lwsp  x0, 4(sp) # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
 c.lwsp  zero, 4(sp) # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
 c.jr  x0 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
 c.jalr  zero # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
-c.addi  x0, x0, 1 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
-c.li  zero, 2 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
-c.slli  zero, zero, 4 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
-c.mv  zero, s0 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
+c.addi  x0, x0, 1 # CHECK: :[[@LINE]]:13: error: immediate must be zero
+c.li  zero, 2 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled
+c.slli  zero, zero, 4 # CHECK: :[[@LINE]]:15: error: invalid operand for instruction
+c.mv  zero, s0 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled
 c.mv  ra, x0 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
 c.add  ra, ra, x0 # CHECK: :[[@LINE]]:16: error: invalid operand for instruction
-c.add  zero, zero, sp # CHECK: :[[@LINE]]:8: error: invalid operand for instruction
+c.add  zero, zero, sp # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
 
 ## GPRNoX0X2
-c.lui x0, 4 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
+c.lui x0, 4 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled
 c.lui x2, 4 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
 
 ## SP
@@ -54,7 +55,7 @@ c.andi a0, %lo(foo) # CHECK: :[[@LINE]]:12: error: immediate must be an integer
 c.andi a0, %hi(foo) # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [-32, 31]
 
 ## simm6nonzero
-c.addi t0, 0 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31]
+c.addi t0, 0 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled
 c.addi t0, -33 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31]
 c.addi t0, 32 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31]
 c.addi t0, foo # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31]
diff --git a/test/MC/RISCV/rv64c-hints-valid.s b/test/MC/RISCV/rv64c-hints-valid.s
new file mode 100644 (file)
index 0000000..5bb773a
--- /dev/null
@@ -0,0 +1,9 @@
+# RUN: llvm-mc %s -triple riscv64 -mattr=+c -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c < %s \
+# RUN:     | llvm-objdump -riscv-no-aliases -d -r - \
+# RUN:     | FileCheck -check-prefixes=CHECK-OBJ,CHECK-ASM-AND-OBJ %s
+
+# CHECK-ASM-AND-OBJ: c.slli zero, 63
+# CHECK-ASM: encoding: [0x7e,0x10]
+c.slli x0, 63
diff --git a/test/MC/RISCV/rvc-hints-invalid.s b/test/MC/RISCV/rvc-hints-invalid.s
new file mode 100644 (file)
index 0000000..5070401
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: not llvm-mc -triple=riscv32 -mattr=+c < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-RV32 %s
+# RUN: not llvm-mc -triple=riscv64 -mattr=+c < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-RV64 %s
+
+c.nop 0 # CHECK: :[[@LINE]]:7: error: immediate must be non-zero in the range [-32, 31]
+
+c.addi x0, 33 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31]
+
+c.li x0, 42 # CHECK: :[[@LINE]]:10: error: immediate must be an integer in the range [-32, 31]
+
+c.lui x0, 0 # CHECK: :[[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31]
+
+c.mv x0, x0 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+
+c.add x0, x0 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
+
+c.slli x0, 0 # CHECK-RV32: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 31]
+c.slli x0, 32 # CHECK-RV32: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 31]
+
+c.slli x0, 0 # CHECK-RV64: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 63]
+
+c.srli64 x30 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+
+c.srai64 x31 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
diff --git a/test/MC/RISCV/rvc-hints-valid.s b/test/MC/RISCV/rvc-hints-valid.s
new file mode 100644 (file)
index 0000000..1302dd8
--- /dev/null
@@ -0,0 +1,63 @@
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+c -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc %s -triple riscv64 -mattr=+c -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+c < %s \
+# RUN:     | llvm-objdump -riscv-no-aliases -d -r - \
+# RUN:     | FileCheck -check-prefixes=CHECK-OBJ,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c < %s \
+# RUN:     | llvm-objdump -riscv-no-aliases -d -r - \
+# RUN:     | FileCheck -check-prefixes=CHECK-OBJ,CHECK-ASM-AND-OBJ %s
+
+# CHECK-ASM-AND-OBJ: c.nop 8
+# CHECK-ASM: encoding: [0x21,0x00]
+c.nop 8
+
+# CHECK-ASM: c.addi zero, 7
+# CHECK-ASM: encoding: [0x1d,0x00]
+# CHECK-OBJ: c.nop 7
+c.addi x0, 7
+
+# CHECK-ASM-AND-OBJ: c.addi a0, 0
+# CHECK-ASM: encoding: [0x01,0x05]
+c.addi a0, 0
+
+# CHECK-ASM-AND-OBJ: c.li zero, 0
+# CHECK-ASM: encoding: [0x01,0x40]
+c.li x0, 0
+
+# CHECK-ASM-AND-OBJ: c.li zero, 1
+# CHECK-ASM: encoding: [0x05,0x40]
+c.li x0, 1
+
+# CHECK-ASM-AND-OBJ: c.lui zero, 1
+# CHECK-ASM: encoding: [0x05,0x60]
+c.lui x0, 1
+
+# CHECK-ASM-AND-OBJ: c.mv zero, a0
+# CHECK-ASM: encoding: [0x2a,0x80]
+c.mv x0, a0
+
+# CHECK-ASM-AND-OBJ: c.add zero, a0
+# CHECK-ASM: encoding: [0x2a,0x90]
+c.add x0, a0
+
+# CHECK-ASM-AND-OBJ: c.slli zero, 1
+# CHECK-ASM: encoding: [0x06,0x00]
+c.slli x0, 1
+
+# CHECK-ASM-AND-OBJ: c.slli64 zero
+# CHECK-ASM: encoding: [0x02,0x00]
+c.slli64 x0
+
+# CHECK-ASM-AND-OBJ: c.slli64 a0
+# CHECK-ASM: encoding: [0x02,0x05]
+c.slli64 a0
+
+# CHECK-ASM-AND-OBJ: c.srli64 a1
+# CHECK-ASM: encoding: [0x81,0x81]
+c.srli64 a1
+
+# CHECK-ASM-AND-OBJ: c.srai64 a0
+# CHECK-ASM: encoding: [0x01,0x85]
+c.srai64 a0