Skip to content

Commit

Permalink
[RISCV] MC layer support for load/store instructions of the C (compre…
Browse files Browse the repository at this point in the history
…ssed) extension

Differential Revision: https://reviews.llvm.org/D40001
    
Patch by Shiva Chen.

llvm-svn: 320037
  • Loading branch information
asb committed Dec 7, 2017
1 parent 87a54d6 commit 9f6aec4
Show file tree
Hide file tree
Showing 15 changed files with 484 additions and 22 deletions.
48 changes: 48 additions & 0 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,38 @@ struct RISCVOperand : public MCParsedAsmOperand {
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;
Expand Down Expand Up @@ -508,6 +540,22 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1);
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);
Expand Down
62 changes: 49 additions & 13 deletions llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,41 @@ static DecodeStatus DecodeFPR64RegisterClass(MCInst &Inst, uint64_t RegNo,
return MCDisassembler::Success;
}

static DecodeStatus DecodeGPRNoX0RegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo == 0) {
return MCDisassembler::Fail;
}

return DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder);
}

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 implied SP operand for instructions *SP compressed instructions. The SP
// operand isn't explicitly encoded in the instruction.
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 <unsigned N>
static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
assert(isUInt<N>(Imm) && "Invalid immediate");
addImplySP(Inst, Address, Decoder);
Inst.addOperand(MCOperand::createImm(Imm));
return MCDisassembler::Success;
}
Expand Down Expand Up @@ -166,19 +197,24 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
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
// 176 bits wide.
Size = 4;
if (Bytes.size() < 4) {
Size = 0;
return MCDisassembler::Fail;
// TODO: This will need modification when supporting instruction set
// extensions with instructions > 32-bits (up to 176 bits wide).
uint32_t Insn;
DecodeStatus Result;

// It's a 32 bit instruction if bit 0 and 1 are 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;
}
12 changes: 10 additions & 2 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,17 @@ enum {
InstFormatB = 5,
InstFormatU = 6,
InstFormatJ = 7,
InstFormatOther = 8,
InstFormatCR = 8,
InstFormatCI = 9,
InstFormatCSS = 10,
InstFormatCIW = 11,
InstFormatCL = 12,
InstFormatCS = 13,
InstFormatCB = 14,
InstFormatCJ = 15,
InstFormatOther = 16,

InstFormatMask = 15
InstFormatMask = 31
};

enum {
Expand Down
22 changes: 19 additions & 3 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,25 @@ MCCodeEmitter *llvm::createRISCVMCCodeEmitter(const MCInstrInfo &MCII,
void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &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<support::little>(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 2: {
uint16_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);
support::endian::Writer<support::little>(OS).write<uint16_t>(Bits);
break;
}
case 4: {
uint32_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);
support::endian::Writer<support::little>(OS).write(Bits);
break;
}
}

++MCNumEmitted; // Keep track of the # of mi's emitted.
}

Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/RISCV/RISCV.td
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ def FeatureStdExtD
def HasStdExtD : Predicate<"Subtarget->hasStdExtD()">,
AssemblerPredicate<"FeatureStdExtD">;

def FeatureStdExtC
: SubtargetFeature<"c", "HasStdExtC", "true",
"'C' (Compressed Instructions)">;
def HasStdExtC : Predicate<"Subtarget->hasStdExtC()">,
AssemblerPredicate<"FeatureStdExtC">;


def Feature64Bit
: SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">;
def IsRV64 : Predicate<"Subtarget->is64Bit()">,
Expand Down
16 changes: 12 additions & 4 deletions llvm/lib/Target/RISCV/RISCVInstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<bits<4> val> {
bits<4> Value = val;
class InstFormat<bits<5> val> {
bits<5> Value = val;
}
def InstFormatPseudo : InstFormat<0>;
def InstFormatR : InstFormat<1>;
Expand All @@ -39,7 +39,15 @@ def InstFormatS : InstFormat<4>;
def InstFormatB : InstFormat<5>;
def InstFormatU : InstFormat<6>;
def InstFormatJ : InstFormat<7>;
def InstFormatOther : InstFormat<8>;
def InstFormatCR : InstFormat<8>;
def InstFormatCI : InstFormat<9>;
def InstFormatCSS : InstFormat<10>;
def InstFormatCIW : InstFormat<11>;
def InstFormatCL : InstFormat<12>;
def InstFormatCS : InstFormat<13>;
def InstFormatCB : InstFormat<14>;
def InstFormatCJ : InstFormat<15>;
def InstFormatOther : InstFormat<16>;

// 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").
Expand Down Expand Up @@ -90,7 +98,7 @@ class RVInst<dag outs, dag ins, string opcodestr, string argstr,
let AsmString = opcodestr # "\t" # argstr;
let Pattern = pattern;

let TSFlags{3-0} = format.Value;
let TSFlags{4-0} = format.Value;
}

// Pseudo instructions
Expand Down
96 changes: 96 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrFormatsC.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//===-- 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 RVInst16<dag outs, dag ins, string opcodestr, string argstr,
list<dag> 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;
}

// The immediate value encoding differs for each instruction, so each subclass
// is responsible for setting the appropriate bits in the Inst field.
// The bits Inst{6-2} must be set for each instruction.
class RVInst16CI<bits<3> funct3, bits<2> opcode, dag outs, dag ins,
string opcodestr, string argstr>
: RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCI> {
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;
}

// The immediate value encoding differs for each instruction, so each subclass
// is responsible for setting the appropriate bits in the Inst field.
// The bits Inst{12-7} must be set for each instruction.
class RVInst16CSS<bits<3> funct3, bits<2> opcode, dag outs, dag ins,
string opcodestr, string argstr>
: RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCSS> {
bits<10> imm;
bits<5> rs2;
bits<5> rs1;

let Inst{15-13} = funct3;
let Inst{6-2} = rs2;
let Inst{1-0} = opcode;
}

// The immediate value encoding differs for each instruction, so each subclass
// is responsible for setting the appropriate bits in the Inst field.
// The bits Inst{12-10} and Inst{6-5} must be set for each instruction.
class RVInst16CL<bits<3> funct3, bits<2> opcode, dag outs, dag ins,
string opcodestr, string argstr>
: RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCL> {
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;
}

// The immediate value encoding differs for each instruction, so each subclass
// is responsible for setting the appropriate bits in the Inst field.
// The bits Inst{12-10} and Inst{6-5} must be set for each instruction.
class RVInst16CS<bits<3> funct3, bits<2> opcode, dag outs, dag ins,
string opcodestr, string argstr>
: RVInst16<outs, ins, opcodestr, argstr, [], InstFormatCS> {
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;
}
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -493,3 +493,4 @@ include "RISCVInstrInfoM.td"
include "RISCVInstrInfoA.td"
include "RISCVInstrInfoF.td"
include "RISCVInstrInfoD.td"
include "RISCVInstrInfoC.td"
Loading

0 comments on commit 9f6aec4

Please sign in to comment.