Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cherry-pick [RISCV] Initial support .insn directive for the assembler. #121

Merged
merged 1 commit into from
Dec 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 62 additions & 1 deletion llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ class RISCVAsmParser : public MCTargetAsmParser {

bool parseDirectiveOption();
bool parseDirectiveAttribute();
bool parseDirectiveInsn(SMLoc L);

void setFeatureBits(uint64_t Feature, StringRef FeatureString) {
if (!(getSTI().getFeatureBits()[Feature])) {
Expand Down Expand Up @@ -504,6 +505,24 @@ struct RISCVOperand : public MCParsedAsmOperand {
return (isRV64() && isUInt<5>(Imm)) || isUInt<4>(Imm);
}

bool isUImm2() const {
int64_t Imm;
RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None;
if (!isImm())
return false;
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
return IsConstantImm && isUInt<2>(Imm) && VK == RISCVMCExpr::VK_RISCV_None;
}

bool isUImm3() const {
int64_t Imm;
RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None;
if (!isImm())
return false;
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
return IsConstantImm && isUInt<3>(Imm) && VK == RISCVMCExpr::VK_RISCV_None;
}

bool isUImm5() const {
int64_t Imm;
RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None;
Expand All @@ -513,6 +532,15 @@ struct RISCVOperand : public MCParsedAsmOperand {
return IsConstantImm && isUInt<5>(Imm) && VK == RISCVMCExpr::VK_RISCV_None;
}

bool isUImm7() const {
int64_t Imm;
RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None;
if (!isImm())
return false;
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
return IsConstantImm && isUInt<7>(Imm) && VK == RISCVMCExpr::VK_RISCV_None;
}

bool isSImm5() const {
if (!isImm())
return false;
Expand Down Expand Up @@ -1835,8 +1863,10 @@ bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) {

if (IDVal == ".option")
return parseDirectiveOption();
else if (IDVal == ".attribute")
if (IDVal == ".attribute")
return parseDirectiveAttribute();
if (IDVal == ".insn")
return parseDirectiveInsn(DirectiveID.getLoc());

return true;
}
Expand Down Expand Up @@ -2200,6 +2230,37 @@ bool RISCVAsmParser::parseDirectiveAttribute() {
return false;
}

/// parseDirectiveInsn
/// ::= .insn [ format encoding, (operands (, operands)*) ]
bool RISCVAsmParser::parseDirectiveInsn(SMLoc L) {
MCAsmParser &Parser = getParser();

// Expect instruction format as identifier.
StringRef Format;
SMLoc ErrorLoc = Parser.getTok().getLoc();
if (Parser.parseIdentifier(Format))
return Error(ErrorLoc, "expected instruction format");

if (Format != "r" && Format != "r4" && Format != "i" && Format != "b" &&
Format != "sb" && Format != "u" && Format != "j" && Format != "uj" &&
Format != "s")
return Error(ErrorLoc, "invalid instruction format");

std::string FormatName = (".insn_" + Format).str();

ParseInstructionInfo Info;
SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> Operands;

if (ParseInstruction(Info, FormatName, L, Operands))
return true;

unsigned Opcode;
uint64_t ErrorInfo;
return MatchAndEmitInstruction(L, Opcode, Operands, Parser.getStreamer(),
ErrorInfo,
/*MatchingInlineAsm=*/false);
}

void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) {
MCInst CInst;
bool Res = compressInst(CInst, Inst, getSTI(), S.getContext());
Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,11 @@ enum {
namespace RISCVOp {
enum OperandType : unsigned {
OPERAND_FIRST_RISCV_IMM = MCOI::OPERAND_FIRST_TARGET,
OPERAND_UIMM4 = OPERAND_FIRST_RISCV_IMM,
OPERAND_UIMM2 = OPERAND_FIRST_RISCV_IMM,
OPERAND_UIMM3,
OPERAND_UIMM4,
OPERAND_UIMM5,
OPERAND_UIMM7,
OPERAND_UIMM12,
OPERAND_SIMM12,
OPERAND_UIMM20,
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
}
} else if (Kind == MCExpr::SymbolRef &&
cast<MCSymbolRefExpr>(Expr)->getKind() == MCSymbolRefExpr::VK_None) {
if (Desc.getOpcode() == RISCV::JAL) {
if (MIFrm == RISCVII::InstFormatJ) {
FixupKind = RISCV::fixup_riscv_jal;
} else if (MIFrm == RISCVII::InstFormatB) {
FixupKind = RISCV::fixup_riscv_branch;
Expand Down
132 changes: 132 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -406,3 +406,135 @@ class RVInstJ<RISCVOpcode opcode, dag outs, dag ins, string opcodestr,
let Inst{11-7} = rd;
let Opcode = opcode.Value;
}

//===----------------------------------------------------------------------===//
// Instruction classes for .insn directives
//===----------------------------------------------------------------------===//

class DirectiveInsnR<dag outs, dag ins, string argstr>
: RVInst<outs, ins, "", "", [], InstFormatR> {
bits<7> opcode;
bits<7> funct7;
bits<3> funct3;

bits<5> rs2;
bits<5> rs1;
bits<5> rd;

let Inst{31-25} = funct7;
let Inst{24-20} = rs2;
let Inst{19-15} = rs1;
let Inst{14-12} = funct3;
let Inst{11-7} = rd;
let Opcode = opcode;

let AsmString = ".insn r " # argstr;
}

class DirectiveInsnR4<dag outs, dag ins, string argstr>
: RVInst<outs, ins, "", "", [], InstFormatR4> {
bits<7> opcode;
bits<2> funct2;
bits<3> funct3;

bits<5> rs3;
bits<5> rs2;
bits<5> rs1;
bits<5> rd;

let Inst{31-27} = rs3;
let Inst{26-25} = funct2;
let Inst{24-20} = rs2;
let Inst{19-15} = rs1;
let Inst{14-12} = funct3;
let Inst{11-7} = rd;
let Opcode = opcode;

let AsmString = ".insn r4 " # argstr;
}

class DirectiveInsnI<dag outs, dag ins, string argstr>
: RVInst<outs, ins, "", "", [], InstFormatI> {
bits<7> opcode;
bits<3> funct3;

bits<12> imm12;
bits<5> rs1;
bits<5> rd;

let Inst{31-20} = imm12;
let Inst{19-15} = rs1;
let Inst{14-12} = funct3;
let Inst{11-7} = rd;
let Opcode = opcode;

let AsmString = ".insn i " # argstr;
}

class DirectiveInsnS<dag outs, dag ins, string argstr>
: RVInst<outs, ins, "", "", [], InstFormatS> {
bits<7> opcode;
bits<3> funct3;

bits<12> imm12;
bits<5> rs2;
bits<5> rs1;

let Inst{31-25} = imm12{11-5};
let Inst{24-20} = rs2;
let Inst{19-15} = rs1;
let Inst{14-12} = funct3;
let Inst{11-7} = imm12{4-0};
let Opcode = opcode;

let AsmString = ".insn s " # argstr;
}

class DirectiveInsnB<dag outs, dag ins, string argstr>
: RVInst<outs, ins, "", "", [], InstFormatB> {
bits<7> opcode;
bits<3> funct3;

bits<12> imm12;
bits<5> rs2;
bits<5> rs1;

let Inst{31} = imm12{11};
let Inst{30-25} = imm12{9-4};
let Inst{24-20} = rs2;
let Inst{19-15} = rs1;
let Inst{14-12} = funct3;
let Inst{11-8} = imm12{3-0};
let Inst{7} = imm12{10};
let Opcode = opcode;

let AsmString = ".insn b " # argstr;
}

class DirectiveInsnU<dag outs, dag ins, string argstr>
: RVInst<outs, ins, "", "", [], InstFormatU> {
bits<7> opcode;

bits<20> imm20;
bits<5> rd;

let Inst{31-12} = imm20;
let Inst{11-7} = rd;
let Opcode = opcode;

let AsmString = ".insn u " # argstr;
}

class DirectiveInsnJ<dag outs, dag ins, string argstr>
: RVInst<outs, ins, "", "", [], InstFormatJ> {
bits<7> opcode;

bits<20> imm20;
bits<5> rd;

let Inst{31-12} = imm20;
let Inst{11-7} = rd;
let Opcode = opcode;

let AsmString = ".insn j " # argstr;
}
102 changes: 102 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,34 @@ def uimmlog2xlen : Operand<XLenVT>, ImmLeaf<XLenVT, [{
let OperandNamespace = "RISCVOp";
}

def uimm2 : Operand<XLenVT> {
let ParserMatchClass = UImmAsmOperand<2>;
let DecoderMethod = "decodeUImmOperand<2>";
let OperandType = "OPERAND_UIMM2";
let OperandNamespace = "RISCVOp";
}

def uimm3 : Operand<XLenVT> {
let ParserMatchClass = UImmAsmOperand<3>;
let DecoderMethod = "decodeUImmOperand<3>";
let OperandType = "OPERAND_UIMM3";
let OperandNamespace = "RISCVOp";
}

def uimm5 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isUInt<5>(Imm);}]> {
let ParserMatchClass = UImmAsmOperand<5>;
let DecoderMethod = "decodeUImmOperand<5>";
let OperandType = "OPERAND_UIMM5";
let OperandNamespace = "RISCVOp";
}

def uimm7 : Operand<XLenVT> {
let ParserMatchClass = UImmAsmOperand<7>;
let DecoderMethod = "decodeUImmOperand<7>";
let OperandType = "OPERAND_UIMM7";
let OperandNamespace = "RISCVOp";
}

def simm12 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isInt<12>(Imm);}]> {
let ParserMatchClass = SImmAsmOperand<12>;
let EncoderMethod = "getImmOpValue";
Expand Down Expand Up @@ -848,6 +869,87 @@ def : MnemonicAlias<"sbreak", "ebreak">;
// that don't support this alias.
def : InstAlias<"zext.b $rd, $rs", (ANDI GPR:$rd, GPR:$rs, 0xFF), 0>;

//===----------------------------------------------------------------------===//
// .insn directive instructions
//===----------------------------------------------------------------------===//

// isCodeGenOnly = 1 to hide them from the tablegened assembly parser.
let isCodeGenOnly = 1, hasSideEffects = 1, mayLoad = 1, mayStore = 1,
hasNoSchedulingInfo = 1 in {
def InsnR : DirectiveInsnR<(outs AnyReg:$rd), (ins uimm7:$opcode, uimm3:$funct3,
uimm7:$funct7, AnyReg:$rs1,
AnyReg:$rs2),
"$opcode, $funct3, $funct7, $rd, $rs1, $rs2">;
def InsnR4 : DirectiveInsnR4<(outs AnyReg:$rd), (ins uimm7:$opcode,
uimm3:$funct3,
uimm2:$funct2,
AnyReg:$rs1, AnyReg:$rs2,
AnyReg:$rs3),
"$opcode, $funct3, $funct2, $rd, $rs1, $rs2, $rs3">;
def InsnI : DirectiveInsnI<(outs AnyReg:$rd), (ins uimm7:$opcode, uimm3:$funct3,
AnyReg:$rs1, simm12:$imm12),
"$opcode, $funct3, $rd, $rs1, $imm12">;
def InsnI_Mem : DirectiveInsnI<(outs AnyReg:$rd), (ins uimm7:$opcode,
uimm3:$funct3,
AnyReg:$rs1,
simm12:$imm12),
"$opcode, $funct3, $rd, ${imm12}(${rs1})">;
def InsnB : DirectiveInsnB<(outs), (ins uimm7:$opcode, uimm3:$funct3,
AnyReg:$rs1, AnyReg:$rs2,
simm13_lsb0:$imm12),
"$opcode, $funct3, $rs1, $rs2, $imm12">;
def InsnU : DirectiveInsnU<(outs AnyReg:$rd), (ins uimm7:$opcode,
uimm20_lui:$imm20),
"$opcode, $rd, $imm20">;
def InsnJ : DirectiveInsnJ<(outs AnyReg:$rd), (ins uimm7:$opcode,
simm21_lsb0_jal:$imm20),
"$opcode, $rd, $imm20">;
def InsnS : DirectiveInsnS<(outs), (ins uimm7:$opcode, uimm3:$funct3,
AnyReg:$rs2, AnyReg:$rs1,
simm12:$imm12),
"$opcode, $funct3, $rs2, ${imm12}(${rs1})">;
}

// Use InstAliases to match these so that we can combine the insn and format
// into a mnemonic to use as the key for the tablegened asm matcher table. The
// parser will take care of creating these fake mnemonics and will only do it
// for known formats.
let EmitPriority = 0 in {
def : InstAlias<".insn_r $opcode, $funct3, $funct7, $rd, $rs1, $rs2",
(InsnR AnyReg:$rd, uimm7:$opcode, uimm3:$funct3, uimm7:$funct7,
AnyReg:$rs1, AnyReg:$rs2)>;
// Accept 4 register form of ".insn r" as alias for ".insn r4".
def : InstAlias<".insn_r $opcode, $funct3, $funct7, $rd, $rs1, $rs2, $rs3",
(InsnR4 AnyReg:$rd, uimm7:$opcode, uimm3:$funct3, uimm7:$funct7,
AnyReg:$rs1, AnyReg:$rs2, AnyReg:$rs3)>;
def : InstAlias<".insn_r4 $opcode, $funct3, $funct7, $rd, $rs1, $rs2, $rs3",
(InsnR4 AnyReg:$rd, uimm7:$opcode, uimm3:$funct3, uimm7:$funct7,
AnyReg:$rs1, AnyReg:$rs2, AnyReg:$rs3)>;
def : InstAlias<".insn_i $opcode, $funct3, $rd, $rs1, $imm12",
(InsnI AnyReg:$rd, uimm7:$opcode, uimm3:$funct3, AnyReg:$rs1,
simm12:$imm12)>;
def : InstAlias<".insn_i $opcode, $funct3, $rd, ${imm12}(${rs1})",
(InsnI_Mem AnyReg:$rd, uimm7:$opcode, uimm3:$funct3,
AnyReg:$rs1, simm12:$imm12)>;
def : InstAlias<".insn_b $opcode, $funct3, $rs1, $rs2, $imm12",
(InsnB uimm7:$opcode, uimm3:$funct3, AnyReg:$rs1,
AnyReg:$rs2, simm13_lsb0:$imm12)>;
// Accept sb as an alias for b.
def : InstAlias<".insn_sb $opcode, $funct3, $rs1, $rs2, $imm12",
(InsnB uimm7:$opcode, uimm3:$funct3, AnyReg:$rs1,
AnyReg:$rs2, simm13_lsb0:$imm12)>;
def : InstAlias<".insn_u $opcode, $rd, $imm20",
(InsnU AnyReg:$rd, uimm7:$opcode, uimm20_lui:$imm20)>;
def : InstAlias<".insn_j $opcode, $rd, $imm20",
(InsnJ AnyReg:$rd, uimm7:$opcode, simm21_lsb0_jal:$imm20)>;
// Accept uj as an alias for j.
def : InstAlias<".insn_uj $opcode, $rd, $imm20",
(InsnJ AnyReg:$rd, uimm7:$opcode, simm21_lsb0_jal:$imm20)>;
def : InstAlias<".insn_s $opcode, $funct3, $rs2, ${imm12}(${rs1})",
(InsnS uimm7:$opcode, uimm3:$funct3, AnyReg:$rs2,
AnyReg:$rs1, simm12:$imm12)>;
}

//===----------------------------------------------------------------------===//
// Pseudo-instructions and codegen patterns
//
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/Target/RISCV/RISCVRegisterInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -557,3 +557,15 @@ foreach m = LMULList.m in {
def FFLAGS : RISCVReg<0, "fflags">;
def FRM : RISCVReg<0, "frm">;
def FCSR : RISCVReg<0, "fcsr">;

// Any type register. Used for .insn directives when we don't know what the
// register types could be.
// NOTE: The alignment and size are bogus values. The Size needs to be non-zero
// or tablegen will use "untyped" to determine the size which will assert.
let isAllocatable = 0 in
def AnyReg : RegisterClass<"RISCV", [untyped], 32,
(add (sequence "X%u", 0, 31),
(sequence "F%u_D", 0, 31),
(sequence "V%u", 0, 31))> {
let Size = 32;
}
Loading