bool parseDirectiveOption();
bool parseDirectiveAttribute();
+ bool parseDirectiveInsn(SMLoc L);
void setFeatureBits(uint64_t Feature, StringRef FeatureString) {
if (!(getSTI().getFeatureBits()[Feature])) {
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;
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;
if (IDVal == ".option")
return parseDirectiveOption();
- else if (IDVal == ".attribute")
+ if (IDVal == ".attribute")
return parseDirectiveAttribute();
+ if (IDVal == ".insn")
+ return parseDirectiveInsn(DirectiveID.getLoc());
return true;
}
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());
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,
}
} 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;
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;
+}
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 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";
// 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
//
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;
+}
--- /dev/null
+# RUN: not llvm-mc -triple riscv32 < %s 2>&1 | FileCheck %s
+
+# Too many operands
+.insn i 0x13, 0, a0, a1, 13, 14 # CHECK: :[[@LINE]]:33: error: invalid operand for instruction
+.insn r 0x43, 0, 0, fa0, fa1, fa2, fa3, fa4 # CHECK: :[[@LINE]]:44: error: invalid operand for instruction
+
+# Too few operands
+.insn r 0x33, 0, 0, a0, a1 # CHECK: :[[@LINE]]:1: error: too few operands for instruction
+.insn i 0x13, 0, a0, a1 # CHECK: :[[@LINE]]:1: error: too few operands for instruction
+
+.insn r 0x33, 0, 0, a0, 13 # CHECK: :[[@LINE]]:28: error: invalid operand for instruction
+.insn i 0x13, 0, a0, a1, a2 # CHECK: :[[@LINE]]:28: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+
+.insn q 0x13, 0, a0, a1, 13, 14 # CHECK: :[[@LINE]]:7: error: invalid instruction format
+
+# Make fake mnemonics we use to match these in the tablegened asm match table isn't exposed.
+.insn_i 0x13, 0, a0, a1, 13, 14 # CHECK: :[[@LINE]]:1: error: unknown directive
--- /dev/null
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+f -riscv-no-aliases -show-encoding \
+# RUN: | FileCheck -check-prefixes=CHECK-ASM %s
+# RUN: llvm-mc %s -triple riscv64 -mattr=+f -riscv-no-aliases -show-encoding \
+# RUN: | FileCheck -check-prefixes=CHECK-ASM %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+f < %s \
+# RUN: | llvm-objdump --mattr=+f -M no-aliases -d -r - \
+# RUN: | FileCheck -check-prefixes=CHECK-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+f < %s \
+# RUN: | llvm-objdump --mattr=+f -M no-aliases -d -r - \
+# RUN: | FileCheck -check-prefixes=CHECK-OBJ %s
+
+target:
+
+# CHECK-ASM: .insn r 51, 0, 0, a0, a1, a2
+# CHECK-ASM: encoding: [0x33,0x85,0xc5,0x00]
+# CHECK-OBJ: add a0, a1, a2
+.insn r 0x33, 0, 0, a0, a1, a2
+
+# CHECK-ASM: .insn i 19, 0, a0, a1, 13
+# CHECK-ASM: encoding: [0x13,0x85,0xd5,0x00]
+# CHECK-OBJ: addi a0, a1, 13
+.insn i 0x13, 0, a0, a1, 13
+
+# CHECK-ASM: .insn i 103, 0, a0, 10(a1)
+# CHECK-ASM: encoding: [0x67,0x85,0xa5,0x00]
+# CHECK-OBJ: jalr a0, 10(a1)
+.insn i 0x67, 0, a0, 10(a1)
+
+# CHECK-ASM: .insn i 3, 0, a0, 4(a1)
+# CHECK-ASM: encoding: [0x03,0x85,0x45,0x00]
+# CHECK-OBJ: lb a0, 4(a1)
+.insn i 0x3, 0, a0, 4(a1)
+
+# CHECK-ASM: .insn b 99, 0, a0, a1, target
+# CHECK-ASM: [0x63'A',A,0xb5'A',A]
+# CHECK-OBJ: beq a0, a1, 0x0 <target>
+.insn sb 0x63, 0, a0, a1, target
+
+# CHECK-ASM: .insn b 99, 0, a0, a1, target
+# CHECK-ASM: [0x63'A',A,0xb5'A',A]
+# CHECK-OBJ: beq a0, a1, 0x0 <target>
+.insn b 0x63, 0, a0, a1, target
+
+# CHECK-ASM: .insn s 35, 0, a0, 4(a1)
+# CHECK-ASM: encoding: [0x23,0x82,0xa5,0x00]
+# CHECK-OBJ: sb a0, 4(a1)
+.insn s 0x23, 0, a0, 4(a1)
+
+# CHECK-ASM: .insn u 55, a0, 4095
+# CHECK-ASM: encoding: [0x37,0xf5,0xff,0x00]
+# CHECK-OBJ: lui a0, 4095
+.insn u 0x37, a0, 0xfff
+
+# CHECK-ASM: .insn j 111, a0, target
+# CHECK-ASM: encoding: [0x6f,0bAAAA0101,A,A]
+# CHECK-OBJ: jal a0, 0x0 <target>
+.insn uj 0x6f, a0, target
+
+# CHECK-ASM: .insn j 111, a0, target
+# CHECK-ASM: encoding: [0x6f,0bAAAA0101,A,A]
+# CHECK-OBJ: jal a0, 0x0 <target>
+.insn j 0x6f, a0, target
+
+# CHECK-ASM: .insn r4 67, 0, 0, fa0, fa1, fa2, fa3
+# CHECK-ASM: encoding: [0x43,0x85,0xc5,0x68]
+# CHECK-OBJ: fmadd.s fa0, fa1, fa2, fa3, rne
+.insn r 0x43, 0, 0, fa0, fa1, fa2, fa3
+
+# CHECK-ASM: .insn r4 67, 0, 0, fa0, fa1, fa2, fa3
+# CHECK-ASM: encoding: [0x43,0x85,0xc5,0x68]
+# CHECK-OBJ: fmadd.s fa0, fa1, fa2, fa3, rne
+.insn r4 0x43, 0, 0, fa0, fa1, fa2, fa3
+
+# CHECK-ASM: .insn i 3, 5, t1, -2048(t2)
+# CHECK-ASM: encoding: [0x03,0xd3,0x03,0x80]
+# CHECK-OBJ: lhu t1, -2048(t2)
+.insn i 0x3, 0x5, x6, %lo(2048)(x7)