This is an archive of the discontinued LLVM Phabricator instance.

[RISCV] Initial support .insn directive for the assembler.
ClosedPublic

Authored by craig.topper on Aug 23 2021, 6:00 PM.

Details

Summary

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

Diff Detail

Event Timeline

craig.topper created this revision.Aug 23 2021, 6:00 PM
craig.topper requested review of this revision.Aug 23 2021, 6:00 PM
Herald added a project: Restricted Project. · View Herald TranscriptAug 23 2021, 6:00 PM
Herald added a subscriber: MaskRay. · View Herald Transcript

Remove stray SystemZ changes.

Remove debug print

craig.topper edited the summary of this revision. (Show Details)Aug 23 2021, 6:38 PM
jrtc27 added inline comments.Aug 27 2021, 3:36 PM
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
2270

I guess MCK__40_ is because of '(' in ASCII... not immediately obvious

2326

Does this not mean you can't, say, have .insn b with a symbol whose name happens to be a register? This seems like it needs to pay more attention to Kind.

2344

Unfortunately it *doesn't* have that first comma, it's a bit ugly like that, though I can see why that was chosen

2356

Plural?

2428

No assignment here, no double parens needed

llvm/lib/Target/RISCV/RISCVInstrInfo.td
1340

Hm, MC stuff is at the top, then CodeGen patterns+pseudos, not sure whether I like having them here or not, but I can see the argument for it, they're their own separate thing...

1364

isCodeGenOnly should be 0 and isAsmParserOnly should be 1, surely?

1369

You could factor out the ".insn X" bit into the directive's class so this just provides an argstr. Also do we want a tab anywhere in the string (either before or after the type) or not?

craig.topper added inline comments.Aug 27 2021, 4:00 PM
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
2270

Yep. I'll add a comment.

2326

Is that an existing bug in instruction parsing?

2344

Yeah, that was copied from SystemZ where I started this patch from before it snowballed. Thanks.

2428

Oops. That must have evolved out of hacking on the code emitted in RISCVGenAsmMatcher.inc

llvm/lib/Target/RISCV/RISCVInstrInfo.td
1364

isAsmParserOnly = 1 would let it go into the tables in RISCVGenAsmMatcher.inc, but we don't want that here.

jrtc27 added inline comments.Aug 27 2021, 4:19 PM
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
2276

Didn't notice this quirk the first time though but eww why was this deemed a good idea all those years ago...

2326

No, that works because the cases where you have bare symbols that require context to know whether to parse a symbol or a register all use custom parsers, which are what MatchOperandParserImpl calls. Only after it's decided it's not a special case does it then return no match and fall back to the generic code like this.

... except it's currently broken for branches. For j sym we make sure to use SImm21Lsb0JAL, but for beq reg, reg, sym we don't use something with a custom parser, just a generic immediate operand. So I guess this does have feature parity after all. Now on my mental list of things to fix...

craig.topper added inline comments.Aug 27 2021, 4:24 PM
llvm/lib/Target/RISCV/RISCVInstrInfo.td
1340

some of the "CodeGen pseudos" are also used by MC, like PseudoLLA.

I'll move these up.

jrtc27 added inline comments.Aug 27 2021, 4:28 PM
llvm/lib/Target/RISCV/RISCVInstrInfo.td
1364

Ah, I've finally gone and looked at what these actually do in the TableGen backends. isCodeGenOnly is more isNotAsmParserNorDisasm and isAsmParserOnly is more isNotDisasm; there isn't really anything to do to opt in/out of CodeGen stuff because that just stems from whether you use it in patterns or custom selection. So yes this is the right option despite what its name says.

craig.topper added inline comments.Aug 27 2021, 4:29 PM
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
2326

Yeah I saw we used the custom parser for j sym so I matched it.

jrtc27 added inline comments.Aug 27 2021, 4:31 PM
llvm/lib/Target/RISCV/RISCVInstrInfo.td
1340

Yeah, that's a good point, we do have a few that have crept into the wrong place. Some of them might have started as CodeGen-only pseudos that later became visible to the AsmParser, but I'm pretty sure they weren't all like that.

craig.topper added inline comments.Aug 27 2021, 4:32 PM
llvm/lib/Target/RISCV/RISCVInstrInfo.td
1397

This should have been .insn s

llvm/test/MC/RISCV/insn.s
45

This should be .insn s

Address review comments

Still need to decide on whether to use a tab.

Fix comment I forgot update

asb added a comment.Sep 2 2021, 5:02 AM

I made a start on .insn support quite some time ago (and unfortunately got distracted with other things and didn't get it to the point it was worth sharing - apologies for that).

I actually had an idea for doing it in a slightly different way vs SystemZ (that SystemZ could hopefully be moved towards as well). Essentially, if we parse .insn like an instruction and not like a directive, we can reuse most of the existing tablegen machinery for asm parsing.

e.g. adding a new hook to AsmParser:

--- a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h
+++ b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h
@@ -416,6 +416,13 @@ public:
   /// \param DirectiveID - the identifier token of the directive.
   virtual bool ParseDirective(AsmToken DirectiveID) = 0;
 
+  /// Return true if the given IDVal should be parsed as a directive. Called
+  /// whenever a "normal" directive is encountered (i.e. not conditional
+  /// assembly directives). Targets may use this to override default parsing
+  /// behaviour, for instance to allow instruction-like directives such as
+  /// .insn to be parsed as an instruction.
+  virtual bool shouldParseAsDirective(StringRef IDVal) { return true; }
+
   /// MatchAndEmitInstruction - Recognize a series of operands of a parsed
   /// instruction as an actual MCInst and emit it to the specified MCStreamer.
   /// This returns false on success and returns true on failure to match.
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index c05f26cbdda5..c3fd85f4a9e0 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -1889,7 +1889,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
   // Otherwise, we have a normal instruction or directive.
 
   // Directives start with "."
-  if (IDVal.startswith(".") && IDVal != ".") {
+  if (IDVal.startswith(".") && IDVal != "." &&
+      getTargetParser().shouldParseAsDirective(IDVal)) {
     // There are several entities interested in parsing directives:
     //
     // 1. The target-specific assembly parser. Some directives are target

Then implement that hook in RISCVAsmParser:

@@ -1756,6 +1808,17 @@ bool RISCVAsmParser::ParseInstruction(ParseInstructionInfo &Info,
   // First operand is token for instruction
   Operands.push_back(RISCVOperand::createToken(Name, NameLoc, isRV64()));
 
+  // If parsing a .insn directive, then create a token containing the
+  // instruction format identifier.
+  if (Name == ".insn") {
+    SMLoc Loc = getLoc();
+    if (!getLexer().is(AsmToken::Identifier))
+      return Error(Loc, ".insn should be followed by an instruction format");
+    StringRef InstFormat = getParser().getTok().getIdentifier();
+    getParser().Lex();
+    Operands.push_back(RISCVOperand::createToken(InstFormat, Loc, isRV64()));
+  }
+
   // If there are no more operands, then finish
   if (getLexer().is(AsmToken::EndOfStatement))
     return false;
@@ -1847,6 +1910,10 @@ bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) {
   return true;
 }
 
+bool RISCVAsmParser::shouldParseAsDirective(StringRef IDVal) {
+  return IDVal != ".insn";
+}
+

Then with some extra machinery for printing opcode values etc, you can make definitions in RISCVInstrInfo.td like:

+//===----------------------------------------------------------------------===//
+// .insn directive
+//===----------------------------------------------------------------------===//
+
+class OpcodeVal<string name, bits<7> enc> {
+  string Name = name;
+  bits<7> Encoding = enc;
+}
+
+def OpcodeValList : GenericTable {
+  let FilterClass = "OpcodeVal";
+  let Fields = [ "Name", "Encoding" ];
+
+  let PrimaryKey = [ "Encoding" ];
+  let PrimaryKeyName = "lookupOpcodeValByEncoding";
+}
+
+def lookupOpcodeValByName : SearchIndex {
+  let Table = OpcodeValList;
+  let Key = [ "Name" ];
+}
+
+// These names match those accepted by the GNU assembler's .insn directive.
+def : OpcodeVal<"C0", 0x0>;
+def : OpcodeVal<"C1", 0x1>;
+def : OpcodeVal<"C2", 0x2>;
+def : OpcodeVal<"LOAD", 0x03>;
+def : OpcodeVal<"LOAD_FP", 0x07>;
+def : OpcodeVal<"CUSTOM_0", 0x0b>;
+def : OpcodeVal<"MISC_MEM", 0x0f>;
+def : OpcodeVal<"OP_IMM", 0x13>;
+def : OpcodeVal<"AUIPC", 0x17>;
+def : OpcodeVal<"OP_IMM_32", 0x1b>;
+def : OpcodeVal<"STORE", 0x23>;
+def : OpcodeVal<"STORE_FP", 0x27>;
+def : OpcodeVal<"CUSTOM_1", 0x2b>;
+def : OpcodeVal<"AMO", 0x2f>;
+def : OpcodeVal<"OP", 0x33>;
+def : OpcodeVal<"LUI", 0x37>;
+def : OpcodeVal<"OP_32", 0x3b>;
+def : OpcodeVal<"MADD", 0x43>;
+def : OpcodeVal<"MSUB", 0x47>;
+def : OpcodeVal<"NMADD", 0x4f>;
+def : OpcodeVal<"NMSUB", 0x4b>;
+def : OpcodeVal<"OP_FP", 0x53>;
+def : OpcodeVal<"CUSTOM_2", 0x5b>;
+def : OpcodeVal<"BRANCH", 0x63>;
+def : OpcodeVal<"JALR", 0x67>;
+def : OpcodeVal<"JAL", 0x6f>;
+def : OpcodeVal<"SYSTEM", 0x73>;
+def : OpcodeVal<"CUSTOM_3", 0x7b>;
+
+// Note that for all directive definitions, the passed constants (e.g. funct3,
+// funct3, opcode) are all dummy values that are overridden by the .insn
+// definition.
+
+let hasSideEffects = 1, mayLoad = 1, mayStore = 1,
+    isAsmParserOnly = 1 in {
+
+def INSN_R : RVInstR<0, 0, OPC_LOAD, (outs GPR:$rd), (ins opcode_value:$opcode,
+                     uimm3:$funct3, uimm7:$funct7, GPR:$rs1, GPR:$rs2),
+                     ".insn r", "$opcode, $funct3, $funct7, $rd, $rs1, $rs2">,
+             Sched<[]> {
+  bits<7> funct7;
+  bits<3> funct3;
+  bits<7> opcode;
+
+  let Inst{31-25} = funct7;
+  let Inst{14-12} = funct3;
+  let Inst{6-0} = opcode;
+}
+
+def INSN_I : RVInstI<0, OPC_LOAD, (outs GPR:$rd), (ins opcode_value:$opcode,
+                     uimm3:$funct3, GPR:$rs1, simm12:$imm12), ".insn i",
+                     "$opcode, $funct3, $rd, $rs1, $imm12">,
+      Sched<[]> {
+  bits<3> funct3;
+  bits<7> opcode;
+
+  let Inst{14-12} = funct3;
+  let Inst{6-0} = opcode;
+}

I'm afraid the branch were I was playing with this got a bit messy so it's hard to extract a full patch, but hopefully that's enough to outline the idea (and I can spend more time pulling bits out if it's useful).

asb added a subscriber: uweigand.Sep 2 2021, 5:19 AM

CC @uweigand in case you have any thoughts in the more tablegen-based approach I suggested in the comment above (i.e. whether you'd be interested in using it for SystemZ if it worked out for RISC-V).

I made a start on .insn support quite some time ago (and unfortunately got distracted with other things and didn't get it to the point it was worth sharing - apologies for that).

I actually had an idea for doing it in a slightly different way vs SystemZ (that SystemZ could hopefully be moved towards as well). Essentially, if we parse .insn like an instruction and not like a directive, we can reuse most of the existing tablegen machinery for asm parsing.

e.g. adding a new hook to AsmParser:

--- a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h
+++ b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h
@@ -416,6 +416,13 @@ public:
   /// \param DirectiveID - the identifier token of the directive.
   virtual bool ParseDirective(AsmToken DirectiveID) = 0;
 
+  /// Return true if the given IDVal should be parsed as a directive. Called
+  /// whenever a "normal" directive is encountered (i.e. not conditional
+  /// assembly directives). Targets may use this to override default parsing
+  /// behaviour, for instance to allow instruction-like directives such as
+  /// .insn to be parsed as an instruction.
+  virtual bool shouldParseAsDirective(StringRef IDVal) { return true; }
+
   /// MatchAndEmitInstruction - Recognize a series of operands of a parsed
   /// instruction as an actual MCInst and emit it to the specified MCStreamer.
   /// This returns false on success and returns true on failure to match.
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index c05f26cbdda5..c3fd85f4a9e0 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -1889,7 +1889,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
   // Otherwise, we have a normal instruction or directive.
 
   // Directives start with "."
-  if (IDVal.startswith(".") && IDVal != ".") {
+  if (IDVal.startswith(".") && IDVal != "." &&
+      getTargetParser().shouldParseAsDirective(IDVal)) {
     // There are several entities interested in parsing directives:
     //
     // 1. The target-specific assembly parser. Some directives are target

Then implement that hook in RISCVAsmParser:

@@ -1756,6 +1808,17 @@ bool RISCVAsmParser::ParseInstruction(ParseInstructionInfo &Info,
   // First operand is token for instruction
   Operands.push_back(RISCVOperand::createToken(Name, NameLoc, isRV64()));
 
+  // If parsing a .insn directive, then create a token containing the
+  // instruction format identifier.
+  if (Name == ".insn") {
+    SMLoc Loc = getLoc();
+    if (!getLexer().is(AsmToken::Identifier))
+      return Error(Loc, ".insn should be followed by an instruction format");
+    StringRef InstFormat = getParser().getTok().getIdentifier();
+    getParser().Lex();
+    Operands.push_back(RISCVOperand::createToken(InstFormat, Loc, isRV64()));
+  }
+
   // If there are no more operands, then finish
   if (getLexer().is(AsmToken::EndOfStatement))
     return false;
@@ -1847,6 +1910,10 @@ bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) {
   return true;
 }
 
+bool RISCVAsmParser::shouldParseAsDirective(StringRef IDVal) {
+  return IDVal != ".insn";
+}
+

Then with some extra machinery for printing opcode values etc, you can make definitions in RISCVInstrInfo.td like:

+//===----------------------------------------------------------------------===//
+// .insn directive
+//===----------------------------------------------------------------------===//
+
+class OpcodeVal<string name, bits<7> enc> {
+  string Name = name;
+  bits<7> Encoding = enc;
+}
+
+def OpcodeValList : GenericTable {
+  let FilterClass = "OpcodeVal";
+  let Fields = [ "Name", "Encoding" ];
+
+  let PrimaryKey = [ "Encoding" ];
+  let PrimaryKeyName = "lookupOpcodeValByEncoding";
+}
+
+def lookupOpcodeValByName : SearchIndex {
+  let Table = OpcodeValList;
+  let Key = [ "Name" ];
+}
+
+// These names match those accepted by the GNU assembler's .insn directive.
+def : OpcodeVal<"C0", 0x0>;
+def : OpcodeVal<"C1", 0x1>;
+def : OpcodeVal<"C2", 0x2>;
+def : OpcodeVal<"LOAD", 0x03>;
+def : OpcodeVal<"LOAD_FP", 0x07>;
+def : OpcodeVal<"CUSTOM_0", 0x0b>;
+def : OpcodeVal<"MISC_MEM", 0x0f>;
+def : OpcodeVal<"OP_IMM", 0x13>;
+def : OpcodeVal<"AUIPC", 0x17>;
+def : OpcodeVal<"OP_IMM_32", 0x1b>;
+def : OpcodeVal<"STORE", 0x23>;
+def : OpcodeVal<"STORE_FP", 0x27>;
+def : OpcodeVal<"CUSTOM_1", 0x2b>;
+def : OpcodeVal<"AMO", 0x2f>;
+def : OpcodeVal<"OP", 0x33>;
+def : OpcodeVal<"LUI", 0x37>;
+def : OpcodeVal<"OP_32", 0x3b>;
+def : OpcodeVal<"MADD", 0x43>;
+def : OpcodeVal<"MSUB", 0x47>;
+def : OpcodeVal<"NMADD", 0x4f>;
+def : OpcodeVal<"NMSUB", 0x4b>;
+def : OpcodeVal<"OP_FP", 0x53>;
+def : OpcodeVal<"CUSTOM_2", 0x5b>;
+def : OpcodeVal<"BRANCH", 0x63>;
+def : OpcodeVal<"JALR", 0x67>;
+def : OpcodeVal<"JAL", 0x6f>;
+def : OpcodeVal<"SYSTEM", 0x73>;
+def : OpcodeVal<"CUSTOM_3", 0x7b>;
+
+// Note that for all directive definitions, the passed constants (e.g. funct3,
+// funct3, opcode) are all dummy values that are overridden by the .insn
+// definition.
+
+let hasSideEffects = 1, mayLoad = 1, mayStore = 1,
+    isAsmParserOnly = 1 in {
+
+def INSN_R : RVInstR<0, 0, OPC_LOAD, (outs GPR:$rd), (ins opcode_value:$opcode,
+                     uimm3:$funct3, uimm7:$funct7, GPR:$rs1, GPR:$rs2),
+                     ".insn r", "$opcode, $funct3, $funct7, $rd, $rs1, $rs2">,
+             Sched<[]> {
+  bits<7> funct7;
+  bits<3> funct3;
+  bits<7> opcode;
+
+  let Inst{31-25} = funct7;
+  let Inst{14-12} = funct3;
+  let Inst{6-0} = opcode;
+}
+
+def INSN_I : RVInstI<0, OPC_LOAD, (outs GPR:$rd), (ins opcode_value:$opcode,
+                     uimm3:$funct3, GPR:$rs1, simm12:$imm12), ".insn i",
+                     "$opcode, $funct3, $rd, $rs1, $imm12">,
+      Sched<[]> {
+  bits<3> funct3;
+  bits<7> opcode;
+
+  let Inst{14-12} = funct3;
+  let Inst{6-0} = opcode;
+}

I'm afraid the branch were I was playing with this got a bit messy so it's hard to extract a full patch, but hopefully that's enough to outline the idea (and I can spend more time pulling bits out if it's useful).

I started looking at this and found one issue immediately.

We ended up with this entry in the custom operand parser

{ 0 /* .insn */, 8 /* 3 */, MCK_SImm21Lsb0JAL, AMFBS_None },

This should be based on the format. Not just ".insn". I think this would cause the operand to fail parsing for any of the formats, but J.

Make some strides in reusing the instruction parsing and matching infrastructure.

clang-format

jrtc27 added inline comments.Sep 9 2021, 12:33 PM
llvm/lib/Target/RISCV/RISCVInstrInfo.td
859

We don't typically indent inside let blocks

896

Will writing .insn_r in the source get picked up by this and thus expose this detail, or be regarded as an unknown directive and thus give an error?

902

R4 ones need an extra space

llvm/lib/Target/RISCV/RISCVRegisterInfo.td
564

XLenVT is wrong, should probably be untyped or Any or something like that. 32 is bogus too but I see we do that for GPR, presumably it's ignored when you use RegInfoByHwMode.

Address review comments.

craig.topper marked 2 inline comments as done.Sep 9 2021, 1:10 PM
craig.topper added inline comments.
llvm/lib/Target/RISCV/RISCVInstrInfo.td
896

It should be hidden. I've added a test to insn_invalid.s

jrtc27 added inline comments.Sep 9 2021, 1:20 PM
llvm/lib/Target/RISCV/RISCVRegisterInfo.td
568

Missed this one last time... but same comment, probably shouldn't be set

craig.topper added inline comments.Sep 9 2021, 1:35 PM
llvm/lib/Target/RISCV/RISCVRegisterInfo.td
568

Removing that caused tablegen to crash. Turns out we either need a valid VT where untyped is or we need a non-zero "let Size =".

Remove the RegInfos but set the size to 32 as a bogus value to keep tablegen from crashing.

jrtc27 added inline comments.Sep 9 2021, 1:46 PM
llvm/lib/Target/RISCV/RISCVRegisterInfo.td
568

Makes sense. This is probably about as good as we can get then without adding some notion of a pseudo register class to tablegen.

jrtc27 added inline comments.Sep 9 2021, 2:00 PM
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
2264
llvm/lib/Target/RISCV/RISCVInstrInfo.td
860

We should probably be marking rd as outs? In a way it doesn't matter (though downstream I think I'll need to inspect the register used for rd to know which relocation to use for jumps; currently I just look at the opcode in RISCVMCCodeEmitter::getImmOpValue but that'll become the ambiguous InsnJ and, eventually, InsnCJ and being able to just get the first def to see what register it is would be slightly easier than having to hard-code which operand number it is) but is technically wrong currently.

Move $rd to outs. Fix formatting

jrtc27 accepted this revision.Sep 9 2021, 2:56 PM

Thanks, looks fine to me now but let's see what others think

This revision is now accepted and ready to land.Sep 9 2021, 2:56 PM
MaskRay added inline comments.Sep 10 2021, 4:53 PM
llvm/lib/Target/RISCV/RISCVInstrInfo.td
905

Does binutils have these .insn_* aliases? I cannot find them.

craig.topper added inline comments.Sep 10 2021, 5:02 PM
llvm/lib/Target/RISCV/RISCVInstrInfo.td
905

No. This was a hack to allow tablegen to have a mnemonic to key the lookup need for tryCustomParseOperand. Anything starting with a . is treated as a directive so will never be parsed as an instruction. There's code in the .insn handling to make this fake mnemonic.

jrtc27 added inline comments.Sep 10 2021, 5:03 PM
llvm/lib/Target/RISCV/RISCVInstrInfo.td
905

No, but see previous discussions. These are internal aliases (which, given they start with a dot, get parsed as directives and thus don't end up checking the match tables, so cannot be used in assembly; see inso-invalid.s for a test of this) to work around TableGen's asm matcher assumption that the mnemonic plus the first argument is enough to disambiguate which instruction to try matching against (there's no way to backtrack, nor to try multiple in parallel).

MaskRay added inline comments.Sep 10 2021, 5:29 PM
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
2257

seems that you can omit L since the opcode is always correct.

Then the argument can be deleted.

craig.topper added inline comments.Sep 10 2021, 5:52 PM
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
2257

L is also passed to MatchAndEmitInstruction and is used for "too few operands for instruction". I guess I could point that at the format operand instead?

MaskRay accepted this revision.Sep 10 2021, 11:22 PM
zixuan-wu added inline comments.
llvm/lib/Target/RISCV/RISCVInstrInfo.td
156

Does it forget to add UIMM2 and UIMM3 verification at verifyInstruction in RISCVInstrInfo.cpp?

zixuan-wu added inline comments.Sep 15 2021, 1:15 AM
llvm/lib/Target/RISCV/RISCVInstrInfo.td
156

And can also make uimm2/uimm3 be instance of ImmLeaf? Which make them reusable to be used in DAG pattern.

zixuan-wu added inline comments.Sep 22 2021, 11:09 PM
llvm/lib/Target/RISCV/RISCVInstrInfo.td
156

It's also missed in match invalid switch like Match_InvalidUImm5 does in RISCVAsmparser.cpp?

Jim added a comment.Sep 22 2021, 11:23 PM

I have uploaded D110307 and D110308 to add missing cases for uimm2, uimm3 and uimm7.

I have uploaded D110307 and D110308 to add missing cases for uimm2, uimm3 and uimm7.

Thank you!