Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -209,6 +209,22 @@ (VK == RISCVMCExpr::VK_RISCV_None || VK == RISCVMCExpr::VK_RISCV_LO); } + 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 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 isUImm12() const { int64_t Imm; RISCVMCExpr::VariantKind VK; @@ -405,6 +421,14 @@ return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 20), (1 << 20) - 2, "immediate must be a multiple of 2 bytes in the range"); + 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_InvalidFenceArg: { SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error( Index: lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp =================================================================== --- lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -81,10 +81,31 @@ return MCDisassembler::Success; } +static DecodeStatus DecodeGPRCRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > sizeof(GPRDecoderTable)) { + 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) { + 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; } @@ -112,24 +133,70 @@ #include "RISCVGenDisassemblerTables.inc" +/// Read two bytes from the ArrayRef and return 16 bit halfword +static DecodeStatus readInstruction16(ArrayRef Bytes, uint64_t Address, + uint64_t &Size, uint32_t &Insn) { + // We want to read exactly 2 Bytes of data. + if (Bytes.size() < 2) { + Size = 0; + return MCDisassembler::Fail; + } + + Insn = (Bytes[1] << 8) | Bytes[0]; + + return MCDisassembler::Success; +} + +/// Read four bytes from the ArrayRef and return 32 bit word +static DecodeStatus readInstruction32(ArrayRef Bytes, uint64_t Address, + uint64_t &Size, uint32_t &Insn) { + // We want to read exactly 4 Bytes of data. + if (Bytes.size() < 4) { + Size = 0; + return MCDisassembler::Fail; + } + + Insn = (Bytes[0] << 0) | (Bytes[1] << 8) | (Bytes[2] << 16) | + (Bytes[3] << 24); + + return MCDisassembler::Success; +} + DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size, ArrayRef Bytes, 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) { + Result = readInstruction32(Bytes, Address, Size, Insn); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + + DEBUG(dbgs() << "Trying RISCV32 table :\n"); + Result = decodeInstruction(DecoderTable32, MI, Insn, Address, this, STI); + Size = 4; + } else { + Result = readInstruction16(Bytes, Address, Size, Insn); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + + 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()); + if (Result != MCDisassembler::Fail) { + return Result; + } - return decodeInstruction(DecoderTable32, MI, Inst, Address, this, STI); + return MCDisassembler::Fail; } Index: lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -29,8 +29,11 @@ InstFormatB = 4, InstFormatU = 5, InstFormatJ = 6, - InstFormatOther = 7, - + InstFormatC = 7, + InstFormatCB = 8, + InstFormatCJ = 9, + InstFormatOther = 10, + InstFormatMask = 15 }; Index: lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -83,9 +83,27 @@ 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); + MCInst TmpInst = MI; + const MCInstrDesc &Desc = MCII.get(TmpInst.getOpcode()); + // Get byte count of instruction + unsigned Size = Desc.getSize(); + assert(Size && "Desc.getSize() returns 0"); + + switch (Size) { + default: + break; + 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,6 +25,11 @@ def HasStdExtA : Predicate<"Subtarget->hasStdExtA()">, AssemblerPredicate<"FeatureStdExtA">; +def FeatureStdExtC : SubtargetFeature<"c", "HasStdExtC", "true", + "'A' (Atomic Instructions)">; +def HasStdExtC : Predicate<"Subtarget->hasStdExtC()">, + AssemblerPredicate<"FeatureStdExtC">; + def Feature64Bit : SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">; Index: lib/Target/RISCV/RISCVInstrFormats.td =================================================================== --- lib/Target/RISCV/RISCVInstrFormats.td +++ lib/Target/RISCV/RISCVInstrFormats.td @@ -38,7 +38,10 @@ def InstFormatB : InstFormat<4>; def InstFormatU : InstFormat<5>; def InstFormatJ : InstFormat<6>; -def InstFormatOther : InstFormat<7>; +def InstFormatC : InstFormat<7>; +def InstFormatCB : InstFormat<8>; +def InstFormatCJ : InstFormat<9>; +def InstFormatOther : InstFormat<10>; // 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"). 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 = asmstr; + let Pattern = pattern; + + let TSFlags{3-0} = format.Value; +} + +class CI funct3, bits<2> opcode, dag outs, dag ins, + string asmstr> + : 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 asmstr> + : 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 asmstr> + : 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 asmstr> + : 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.cpp =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.cpp +++ lib/Target/RISCV/RISCVInstrInfo.cpp @@ -52,7 +52,7 @@ if (I != MBB.end()) DL = I->getDebugLoc(); - if (RC == &RISCV::GPRRegClass) + if (RC == &RISCV::GPRRegClass || RC == &RISCV::GPRCRegClass) BuildMI(MBB, I, DL, get(RISCV::SW)) .addReg(SrcReg, getKillRegState(IsKill)) .addFrameIndex(FI) @@ -70,7 +70,7 @@ if (I != MBB.end()) DL = I->getDebugLoc(); - if (RC == &RISCV::GPRRegClass) + if (RC == &RISCV::GPRRegClass || RC == &RISCV::GPRCRegClass) BuildMI(MBB, I, DL, get(RISCV::LW), DstReg).addFrameIndex(FI).addImm(0); else llvm_unreachable("Can't load this register from stack slot"); 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,93 @@ +//===- 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 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 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>"; +} + +//===----------------------------------------------------------------------===// +// Instruction Class Templates +//===----------------------------------------------------------------------===// + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +class Stack_Load funct3, string OpcodeStr, + RegisterClass cls> : + CI; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +class Stack_Store funct3, string OpcodeStr, + RegisterClass cls> : + CSS; + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +class Reg_Load funct3, string OpcodeStr, SDPatternOperator Op, + RegisterClass cls> : + CL; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +class Reg_Store funct3, string OpcodeStr, SDPatternOperator Op, + RegisterClass cls> : + CS; + +//===----------------------------------------------------------------------===// +// Stack-Pointer-Based Loads and Stores +//===----------------------------------------------------------------------===// + +def CLWSP : Stack_Load<0b010, "c.lwsp", GPR>, + Requires<[HasStdExtC]> { + let Inst{6-4} = imm{4-2}; + let Inst{3-2} = imm{7-6}; +} + +def CSWSP : Stack_Store<0b110, "c.swsp", GPR>, + Requires<[HasStdExtC]> { + let Inst{12-9} = imm{5-2}; + let Inst{8-7} = imm{7-6}; +} + +//===----------------------------------------------------------------------===// +// Register-Based Loads and Stores +//===----------------------------------------------------------------------===// + +def CLW : Reg_Load<0b010, "c.lw", load, GPRC>, 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", store, GPRC>, + Requires<[HasStdExtC]> { + bits<7> imm; + let Inst{12-10} = imm{5-3}; + let Inst{6} = imm{2}; + let Inst{5} = imm{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/compressed-invalid.s =================================================================== --- /dev/null +++ test/MC/RISCV/compressed-invalid.s @@ -0,0 +1,14 @@ +# RUN: not llvm-mc -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/compressed-valid.s =================================================================== --- /dev/null +++ test/MC/RISCV/compressed-valid.s @@ -0,0 +1,17 @@ +# RUN: llvm-mc %s -mattr=+c -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s +# RUN: llvm-mc -filetype=obj -mattr=+c < %s \ +# RUN: | llvm-objdump -d -mattr=+c - | 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)