Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -194,6 +194,38 @@ return IsConstantImm && isUInt<5>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; } + bool isUImm7Lsb00() const { + int64_t Imm; + RISCVMCExpr::VariantKind VK; + bool IsConstantImm = evaluateConstantImm(Imm, VK); + return IsConstantImm && isShiftedUInt<5, 2>(Imm) && + VK == RISCVMCExpr::VK_RISCV_None; + } + + bool isUImm8Lsb00() const { + int64_t Imm; + RISCVMCExpr::VariantKind VK; + bool IsConstantImm = evaluateConstantImm(Imm, VK); + return IsConstantImm && isShiftedUInt<6, 2>(Imm) && + VK == RISCVMCExpr::VK_RISCV_None; + } + + bool isUImm8Lsb000() const { + int64_t Imm; + RISCVMCExpr::VariantKind VK; + bool IsConstantImm = evaluateConstantImm(Imm, VK); + return IsConstantImm && isShiftedUInt<5, 3>(Imm) && + VK == RISCVMCExpr::VK_RISCV_None; + } + + bool isUImm9Lsb000() const { + int64_t Imm; + RISCVMCExpr::VariantKind VK; + bool IsConstantImm = evaluateConstantImm(Imm, VK); + return IsConstantImm && isShiftedUInt<6, 3>(Imm) && + VK == RISCVMCExpr::VK_RISCV_None; + } + bool isSImm12() const { RISCVMCExpr::VariantKind VK; int64_t Imm; @@ -390,6 +422,22 @@ } case Match_InvalidUImm5: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); + case Match_InvalidUImm7Lsb00: + return generateImmOutOfRangeError( + Operands, ErrorInfo, 0, (1 << 7) - 4, + "immediate must be a multiple of 4 bytes in the range"); + case Match_InvalidUImm8Lsb00: + return generateImmOutOfRangeError( + Operands, ErrorInfo, 0, (1 << 8) - 4, + "immediate must be a multiple of 4 bytes in the range"); + case Match_InvalidUImm8Lsb000: + return generateImmOutOfRangeError( + Operands, ErrorInfo, 0, (1 << 8) - 8, + "immediate must be a multiple of 8 bytes in the range"); + case Match_InvalidUImm9Lsb000: + return generateImmOutOfRangeError( + Operands, ErrorInfo, 0, (1 << 9) - 8, + "immediate must be a multiple of 8 bytes in the range"); case Match_InvalidSImm12: return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 11), (1 << 11) - 1); Index: lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp =================================================================== --- lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -81,10 +81,33 @@ return MCDisassembler::Success; } +static DecodeStatus DecodeGPRCRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 8) { + return MCDisassembler::Fail; + } + unsigned Reg = GPRDecoderTable[RegNo + 8]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +// Add Imply SP operand for SP imply instructions(The instruction SP not encode +// in bit field) +static void addImplySP(MCInst &Inst, int64_t Address, const void *Decoder) { + if (Inst.getOpcode() == RISCV::CLWSP || + Inst.getOpcode() == RISCV::CSWSP || + Inst.getOpcode() == RISCV::CLDSP || + Inst.getOpcode() == RISCV::CSDSP) { + DecodeGPRRegisterClass(Inst, 2, Address, Decoder); + } +} + template static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm, int64_t Address, const void *Decoder) { assert(isUInt(Imm) && "Invalid immediate"); + addImplySP(Inst, Address, Decoder); Inst.addOperand(MCOperand::createImm(Imm)); return MCDisassembler::Success; } @@ -117,19 +140,26 @@ uint64_t Address, raw_ostream &OS, raw_ostream &CS) const { - // TODO: although assuming 4-byte instructions is sufficient for RV32 and - // RV64, this will need modification when supporting the compressed - // instruction set extension (RVC) which uses 16-bit instructions. Other - // instruction set extensions have the option of defining instructions up to + // TODO: This will need modification when supporting the instruction + // set extensions have the option of defining instructions up to // 176 bits wide. - Size = 4; - if (Bytes.size() < 4) { - Size = 0; - return MCDisassembler::Fail; + uint32_t Insn; + DecodeStatus Result; + + // It's a 32 bit instruction if bit 0 and 1 is 1. + if ((Bytes[0] & 0x3) == 0x3) { + Insn = support::endian::read32le(Bytes.data()); + DEBUG(dbgs() << "Trying RISCV32 table :\n"); + Result = decodeInstruction(DecoderTable32, MI, Insn, Address, this, STI); + Size = 4; + } else { + Insn = support::endian::read16le(Bytes.data()); + DEBUG(dbgs() << "Trying RISCV_C table (16-bit Instruction):\n"); + // Calling the auto-generated decoder function. + Result = + decodeInstruction(DecoderTable16, MI, Insn, Address, this, STI); + Size = 2; } - // Get the four bytes of the instruction. - uint32_t Inst = support::endian::read32le(Bytes.data()); - - return decodeInstruction(DecoderTable32, MI, Inst, Address, this, STI); + return Result; } Index: lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -29,9 +29,17 @@ InstFormatB = 4, InstFormatU = 5, InstFormatJ = 6, - InstFormatOther = 7, + InstFormatCR = 7, + InstFormatCI = 8, + InstFormatCSS = 9, + InstFormatCIW = 10, + InstFormatCL = 11, + InstFormatCS = 12, + InstFormatCB = 13, + InstFormatCJ = 14, + InstFormatOther = 15, - InstFormatMask = 15 + InstFormatMask = 31 }; enum { Index: lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -83,9 +83,25 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { - // For now, we only support RISC-V instructions with 32-bit length - uint32_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); - support::endian::Writer(OS).write(Bits); + const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); + // Get byte count of instruction + unsigned Size = Desc.getSize(); + + switch (Size) { + default: + llvm_unreachable("Unhandled encodeInstruction length!"); + case 4: { + uint32_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); + support::endian::Writer(OS).write(Bits); + break; + } + case 2: { + uint16_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); + support::endian::Writer(OS).write(Bits); + break; + } + } + ++MCNumEmitted; // Keep track of the # of mi's emitted. } Index: lib/Target/RISCV/RISCV.td =================================================================== --- lib/Target/RISCV/RISCV.td +++ lib/Target/RISCV/RISCV.td @@ -25,8 +25,16 @@ def HasStdExtA : Predicate<"Subtarget->hasStdExtA()">, AssemblerPredicate<"FeatureStdExtA">; +def FeatureStdExtC + : SubtargetFeature<"c", "HasStdExtC", "true", + "'C' (Compress Instructions)">; +def HasStdExtC : Predicate<"Subtarget->hasStdExtC()">, + AssemblerPredicate<"FeatureStdExtC">; + def Feature64Bit : SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">; +def IsRV64 : Predicate<"Subtarget->is64Bit()">, + AssemblerPredicate<"Feature64Bit">; def RV64 : HwMode<"+64bit">; def RV32 : HwMode<"-64bit">; Index: lib/Target/RISCV/RISCVInstrFormats.td =================================================================== --- lib/Target/RISCV/RISCVInstrFormats.td +++ lib/Target/RISCV/RISCVInstrFormats.td @@ -28,8 +28,8 @@ // Format specifies the encoding used by the instruction. This is used by // RISCVMCCodeEmitter to determine which form of fixup to use. These // definitions must be kept in-sync with RISCVBaseInfo.h. -class InstFormat val> { - bits<4> Value = val; +class InstFormat val> { + bits<5> Value = val; } def InstFormatPseudo : InstFormat<0>; def InstFormatR : InstFormat<1>; @@ -38,7 +38,15 @@ def InstFormatB : InstFormat<4>; def InstFormatU : InstFormat<5>; def InstFormatJ : InstFormat<6>; -def InstFormatOther : InstFormat<7>; +def InstFormatCR : InstFormat<7>; +def InstFormatCI : InstFormat<8>; +def InstFormatCSS : InstFormat<9>; +def InstFormatCIW : InstFormat<10>; +def InstFormatCL : InstFormat<11>; +def InstFormatCS : InstFormat<12>; +def InstFormatCB : InstFormat<13>; +def InstFormatCJ : InstFormat<14>; +def InstFormatOther : InstFormat<15>; // The following opcode names and match those given in Table 19.1 in the // RISC-V User-level ISA specification ("RISC-V base opcode map"). @@ -89,7 +97,7 @@ let AsmString = opcodestr # "\t" # argstr; let Pattern = pattern; - let TSFlags{3-0} = format.Value; + let TSFlags{4-0} = format.Value; } // Pseudo instructions Index: lib/Target/RISCV/RISCVInstrFormatsC.td =================================================================== --- /dev/null +++ lib/Target/RISCV/RISCVInstrFormatsC.td @@ -0,0 +1,84 @@ +//===-- RISCVInstrFormatsC.td - RISCV C Instruction Formats --*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the RISC-V C extension instruction formats. +// +//===----------------------------------------------------------------------===// + +class RV16Inst pattern, InstFormat format> + : Instruction { + field bits<16> Inst; + // SoftFail is a field the disassembler can use to provide a way for + // instructions to not match without killing the whole decode process. It is + // mainly used for ARM, but Tablegen expects this field to exist or it fails + // to build the decode table. + field bits<16> SoftFail = 0; + let Size = 2; + + bits<2> Opcode = 0; + + let Namespace = "RISCV"; + + dag OutOperandList = outs; + dag InOperandList = ins; + let AsmString = opcodestr # "\t" # argstr; + let Pattern = pattern; + + let TSFlags{4-0} = format.Value; +} + +class CI funct3, bits<2> opcode, dag outs, dag ins, + string opcodestr, string argstr> + : RV16Inst { + bits<10> imm; + bits<5> rd; + bits<5> rs1; + + let Inst{15-13} = funct3; + let Inst{12} = imm{5}; + let Inst{11-7} = rd; + let Inst{1-0} = opcode; +} + +class CSS funct3, bits<2> opcode, dag outs, dag ins, + string opcodestr, string argstr> + : RV16Inst { + bits<10> imm; + bits<5> rs2; + bits<5> rs1; + + let Inst{15-13} = funct3; + let Inst{6-2} = rs2; + let Inst{1-0} = opcode; +} + +class CL funct3, bits<2> opcode, dag outs, dag ins, + string opcodestr, string argstr> + : RV16Inst { + bits<3> rd; + bits<3> rs1; + + let Inst{15-13} = funct3; + let Inst{9-7} = rs1; + let Inst{4-2} = rd; + let Inst{1-0} = opcode; +} + +class CS funct3, bits<2> opcode, dag outs, dag ins, + string opcodestr, string argstr> + : RV16Inst { + bits<3> rs2; + bits<3> rs1; + + let Inst{15-13} = funct3; + let Inst{9-7} = rs1; + let Inst{4-2} = rs2; + let Inst{1-0} = opcode; +} Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -406,3 +406,4 @@ include "RISCVInstrInfoM.td" include "RISCVInstrInfoA.td" +include "RISCVInstrInfoC.td" Index: lib/Target/RISCV/RISCVInstrInfoC.td =================================================================== --- /dev/null +++ lib/Target/RISCV/RISCVInstrInfoC.td @@ -0,0 +1,132 @@ +//===- RISCVInstrInfoC.td - Compressed RISCV instructions -*- tblgen-*-----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +include "RISCVInstrFormatsC.td" + +//===----------------------------------------------------------------------===// +// Operand definitions. +//===----------------------------------------------------------------------===// + +// A 7-bit unsigned immediate where the least two bits are zero. +def uimm7_lsb00 : Operand, + ImmLeaf(Imm);}]> { + let ParserMatchClass = UImmAsmOperand<7, "Lsb00">; + let EncoderMethod = "getImmOpValue"; + let DecoderMethod = "decodeUImmOperand<7>"; +} + +// A 8-bit unsigned immediate where the least two bits are zero. +def uimm8_lsb00 : Operand, + ImmLeaf(Imm);}]> { + let ParserMatchClass = UImmAsmOperand<8, "Lsb00">; + let EncoderMethod = "getImmOpValue"; + let DecoderMethod = "decodeUImmOperand<8>"; +} + +// A 8-bit unsigned immediate where the least three bits are zero. +def uimm8_lsb000 : Operand, + ImmLeaf(Imm);}]> { + let ParserMatchClass = UImmAsmOperand<8, "Lsb000">; + let EncoderMethod = "getImmOpValue"; + let DecoderMethod = "decodeUImmOperand<8>"; +} + +// A 9-bit unsigned immediate where the least three bits are zero. +def uimm9_lsb000 : Operand, + ImmLeaf(Imm);}]> { + let ParserMatchClass = UImmAsmOperand<9, "Lsb000">; + let EncoderMethod = "getImmOpValue"; + let DecoderMethod = "decodeUImmOperand<9>"; +} + +//===----------------------------------------------------------------------===// +// Instruction Class Templates +//===----------------------------------------------------------------------===// + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +class Stack_Load funct3, string OpcodeStr, + RegisterClass cls, DAGOperand opnd> : + CI; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +class Stack_Store funct3, string OpcodeStr, + RegisterClass cls, DAGOperand opnd> : + CSS; + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +class Reg_Load funct3, string OpcodeStr, + RegisterClass cls, DAGOperand opnd> : + CL; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +class Reg_Store funct3, string OpcodeStr, + RegisterClass cls, DAGOperand opnd> : + CS; + +//===----------------------------------------------------------------------===// +// Instructions +//===----------------------------------------------------------------------===// + +def CLWSP : Stack_Load<0b010, "c.lwsp", GPR, uimm8_lsb00>, + Requires<[HasStdExtC]> { + let Inst{6-4} = imm{4-2}; + let Inst{3-2} = imm{7-6}; +} + +def CSWSP : Stack_Store<0b110, "c.swsp", GPR, uimm8_lsb00>, + Requires<[HasStdExtC]> { + let Inst{12-9} = imm{5-2}; + let Inst{8-7} = imm{7-6}; +} + +def CLDSP : Stack_Load<0b011, "c.ldsp", GPR, uimm9_lsb000>, + Requires<[HasStdExtC, IsRV64]> { + let Inst{6-5} = imm{4-3}; + let Inst{4-2} = imm{8-6}; +} + +def CSDSP : Stack_Store<0b111, "c.sdsp", GPR, uimm9_lsb000>, + Requires<[HasStdExtC, IsRV64]> { + let Inst{12-10} = imm{5-3}; + let Inst{9-7} = imm{8-6}; +} + +def CLW : Reg_Load<0b010, "c.lw", GPRC, uimm7_lsb00>, + Requires<[HasStdExtC]> { + bits<7> imm; + let Inst{12-10} = imm{5-3}; + let Inst{6} = imm{2}; + let Inst{5} = imm{6}; +} + +def CSW : Reg_Store<0b110, "c.sw", GPRC, uimm7_lsb00>, + Requires<[HasStdExtC]> { + bits<7> imm; + let Inst{12-10} = imm{5-3}; + let Inst{6} = imm{2}; + let Inst{5} = imm{6}; +} + +def CLD : Reg_Load<0b011, "c.ld", GPRC, uimm8_lsb000>, + Requires<[HasStdExtC, IsRV64]> { + bits<8> imm; + let Inst{12-10} = imm{5-3}; + let Inst{6-5} = imm{7-6}; +} + +def CSD : Reg_Store<0b111, "c.sd", GPRC, uimm8_lsb000>, + Requires<[HasStdExtC, IsRV64]> { + bits<8> imm; + let Inst{12-10} = imm{5-3}; + let Inst{6-5} = imm{7-6}; +} Index: lib/Target/RISCV/RISCVRegisterInfo.td =================================================================== --- lib/Target/RISCV/RISCVRegisterInfo.td +++ lib/Target/RISCV/RISCVRegisterInfo.td @@ -72,3 +72,18 @@ [RV32, RV64, DefaultMode], [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>; } + +def GPRC : RegisterClass<"RISCV", [XLenVT], 32, (add + (sequence "X%u", 10, 15), + (sequence "X%u", 8, 9) + )> { + let RegInfos = RegInfoByHwMode< + [RV32, RV64, DefaultMode], + [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>; +} + +def SP : RegisterClass<"RISCV", [XLenVT], 32, (add X2)> { + let RegInfos = RegInfoByHwMode< + [RV32, RV64, DefaultMode], + [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>; +} Index: lib/Target/RISCV/RISCVSubtarget.h =================================================================== --- lib/Target/RISCV/RISCVSubtarget.h +++ lib/Target/RISCV/RISCVSubtarget.h @@ -32,6 +32,7 @@ virtual void anchor(); bool HasStdExtM = false; bool HasStdExtA = false; + bool HasStdExtC = false; bool HasRV64 = false; unsigned XLen = 32; MVT XLenVT = MVT::i32; @@ -70,6 +71,7 @@ } bool hasStdExtM() const { return HasStdExtM; } bool hasStdExtA() const { return HasStdExtA; } + bool hasStdExtC() const { return HasStdExtC; } bool is64Bit() const { return HasRV64; } MVT getXLenVT() const { return XLenVT; } unsigned getXLen() const { return XLen; } Index: test/MC/RISCV/rv32c-invalid.s =================================================================== --- /dev/null +++ test/MC/RISCV/rv32c-invalid.s @@ -0,0 +1,14 @@ +# RUN: not llvm-mc -triple=riscv32 -mattr=+c < %s 2>&1 | FileCheck %s + +## GPRC +c.lw ra, 4(sp) # CHECK: :[[@LINE]]:7: error: invalid operand for instruction +c.sw sp, 4(sp) # CHECK: :[[@LINE]]:7: error: invalid operand for instruction + +# Out of range immediates + +## uimm8_lsb00 +c.lwsp ra, 300(sp) # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 4 bytes in the range [0, 252] +c.swsp ra, -20(sp) # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 4 bytes in the range [0, 252] +## uimm7_lsb00 +c.lw s0, -4(sp) # CHECK: :[[@LINE]]:11: error: immediate must be a multiple of 4 bytes in the range [0, 124] +c.sw s0, 130(sp) # CHECK: :[[@LINE]]:11: error: immediate must be a multiple of 4 bytes in the range [0, 124] Index: test/MC/RISCV/rv32c-valid.s =================================================================== --- /dev/null +++ test/MC/RISCV/rv32c-valid.s @@ -0,0 +1,22 @@ +# RUN: llvm-mc -triple=riscv32 -mattr=+c -show-encoding < %s \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s +# RUN: llvm-mc -triple=riscv64 -mattr=+c,+64bit -show-encoding < %s \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \ +# RUN: | llvm-objdump -mattr=+c -d - | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c,+64bit < %s \ +# RUN: | llvm-objdump -mattr=+c,+64bit -d - | FileCheck -check-prefix=CHECK-INST %s + + +# CHECK-INST: c.lwsp ra, 12(sp) +# CHECK: encoding: [0xb2,0x40] +c.lwsp ra, 12(sp) +# CHECK-INST: c.swsp ra, 12(sp) +# CHECK: encoding: [0x06,0xc6] +c.swsp ra, 12(sp) +# CHECK-INST: c.lw a2, 4(a0) +# CHECK: encoding: [0x50,0x41] +c.lw a2, 4(a0) +# CHECK-INST: c.sw a5, 8(a3) +# CHECK: encoding: [0x9c,0xc6] +c.sw a5, 8(a3) Index: test/MC/RISCV/rv64c-invalid.s =================================================================== --- /dev/null +++ test/MC/RISCV/rv64c-invalid.s @@ -0,0 +1,14 @@ +# RUN: not llvm-mc -triple=riscv64 -mattr=+c,+64bit < %s 2>&1 | FileCheck %s + +## GPRC +c.ld ra, 4(sp) # CHECK: :[[@LINE]]:6: error: invalid operand for instruction +c.sd sp, 4(sp) # CHECK: :[[@LINE]]:6: error: invalid operand for instruction + +# Out of range immediates + +## uimm9_lsb000 +c.ldsp ra, 300(sp) # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 8 bytes in the range [0, 504] +c.sdsp ra, -20(sp) # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 8 bytes in the range [0, 504] +## uimm8_lsb000 +c.ld s0, -4(sp) # CHECK: :[[@LINE]]:11: error: immediate must be a multiple of 8 bytes in the range [0, 248] +c.sd s0, 130(sp) # CHECK: :[[@LINE]]:11: error: immediate must be a multiple of 8 bytes in the range [0, 248] Index: test/MC/RISCV/rv64c-valid.s =================================================================== --- /dev/null +++ test/MC/RISCV/rv64c-valid.s @@ -0,0 +1,18 @@ +# RUN: llvm-mc -triple=riscv64 -mattr=+c,+64bit -show-encoding < %s \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c,+64bit < %s \ +# RUN: | llvm-objdump -mattr=+c,+64bit -d - | FileCheck -check-prefix=CHECK-INST %s + +.LBB0_3: +# CHECK-INST: c.ldsp ra, 8(sp) +# CHECK: encoding: [0xa2,0x60] +c.ldsp ra, 8(sp) +# CHECK-INST: c.sdsp ra, 8(sp) +# CHECK: encoding: [0x06,0xe4] +c.sdsp ra, 8(sp) +# CHECK-INST: c.ld a4, 16(a3) +# CHECK: encoding: [0x98,0x6a] +c.ld a4, 16(a3) +# CHECK-INST: c.sd a5, 24(a3) +# CHECK: encoding: [0x9c,0xee] +c.sd a5, 24(a3)