[llvm] 2838797 - [RISCV] Initial support .insn directive for the assembler.
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 12 16:07:59 PDT 2021
Author: Craig Topper
Date: 2021-09-12T15:56:12-07:00
New Revision: 283879793dc787225992496587581ec77b6b0610
URL: https://github.com/llvm/llvm-project/commit/283879793dc787225992496587581ec77b6b0610
DIFF: https://github.com/llvm/llvm-project/commit/283879793dc787225992496587581ec77b6b0610.diff
LOG: [RISCV] Initial support .insn directive for the assembler.
This allows for a custom encoding to be emitted. It can also be
used with inline assembly to allow the custom instruction to be
register allocated like other instructions.
I initially started from SystemZ's implementation, but some of
the formats allow operands to be specified in multiple ways so I
had to add support for matching different operand class lists for
the same format. That implementation is a simplified version of
what is emitted by tablegen for regular instructions.
I've left out the compressed formats. And I haven't supported the
named opcodes like LUI or OP_IMM_32. Those can be added in future
patches.
Documentation can be found here https://sourceware.org/binutils/docs-2.37/as/RISC_002dV_002dFormats.html
Reviewed By: jrtc27, MaskRay
Differential Revision: https://reviews.llvm.org/D108602
Added:
llvm/test/MC/RISCV/insn-invalid.s
llvm/test/MC/RISCV/insn.s
Modified:
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
llvm/lib/Target/RISCV/RISCVInstrFormats.td
llvm/lib/Target/RISCV/RISCVInstrInfo.td
llvm/lib/Target/RISCV/RISCVRegisterInfo.td
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index c3ccec10d804b..b2aa585a2ba33 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -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])) {
@@ -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;
@@ -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;
@@ -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;
}
@@ -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());
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index f271d519182bc..ed85e6fa3f248 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -168,8 +168,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,
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 1ef276b101003..14d0191a505fc 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -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;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrFormats.td b/llvm/lib/Target/RISCV/RISCVInstrFormats.td
index 8c198989d634d..a6e2710949b26 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrFormats.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrFormats.td
@@ -409,3 +409,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;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 495c39132ca31..86e715ffdb75e 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -153,6 +153,20 @@ 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>";
@@ -160,6 +174,13 @@ def uimm5 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isUInt<5>(Imm);}]> {
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";
@@ -849,6 +870,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
//
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
index 9b4d3986360fc..179494071c9d1 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
@@ -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;
+}
diff --git a/llvm/test/MC/RISCV/insn-invalid.s b/llvm/test/MC/RISCV/insn-invalid.s
new file mode 100644
index 0000000000000..5d7eaf69f01dc
--- /dev/null
+++ b/llvm/test/MC/RISCV/insn-invalid.s
@@ -0,0 +1,17 @@
+# 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
diff --git a/llvm/test/MC/RISCV/insn.s b/llvm/test/MC/RISCV/insn.s
new file mode 100644
index 0000000000000..1e02e22f965ad
--- /dev/null
+++ b/llvm/test/MC/RISCV/insn.s
@@ -0,0 +1,77 @@
+# 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)
More information about the llvm-commits
mailing list