[AsmParser] Match mandatory operands following optional operands.
authorIvan Kosarev <ivan.kosarev@amd.com>
Thu, 10 Nov 2022 12:19:53 +0000 (12:19 +0000)
committerIvan Kosarev <ivan.kosarev@amd.com>
Thu, 10 Nov 2022 12:48:11 +0000 (12:48 +0000)
Currently, the asm parser stops matching instruction operands as soon as the first optional operand is encountered. This leads to the need for custom checks on missing mandatory operands that come after optional operands.

The patch changes the parser to always match all optional and mandatory instruction operands, thus making the custom checks unnecessary. This is particularly useful for the AMDGPU backend where we have numerous optional instruction modifiers.

Reviewed By: dp

Differential Revision: https://reviews.llvm.org/D137549

llvm/test/MC/AMDGPU/gfx10_err_pos.s
llvm/test/MC/AMDGPU/gfx9-asm-err.s
llvm/test/MC/AMDGPU/gfx9_err_pos.s
llvm/test/MC/AMDGPU/mubuf.s
llvm/test/MC/SystemZ/asm-match.s
llvm/test/MC/X86/x86_64-asm-match.s
llvm/utils/TableGen/AsmMatcherEmitter.cpp

index 3fee1c0..38440d4 100644 (file)
@@ -1,10 +1,10 @@
 // RUN: not llvm-mc -arch=amdgcn -mcpu=gfx1010 -mattr=+WavefrontSize32,-WavefrontSize64 %s 2>&1 | FileCheck %s --implicit-check-not=error: --strict-whitespace
 
 //==============================================================================
-// dim modifier is required on this GPU
+// operands are not valid for this GPU or mode
 
 image_atomic_add v252, v2, s[8:15]
-// CHECK: error: dim modifier is required on this GPU
+// CHECK: error: operands are not valid for this GPU or mode
 // CHECK-NEXT:{{^}}image_atomic_add v252, v2, s[8:15]
 // CHECK-NEXT:{{^}}^
 
@@ -967,19 +967,6 @@ s_sendmsg sendmsg(MSG_GS_DONE, GS_OP_NOP, 0)
 // CHECK-NEXT:{{^}}                                          ^
 
 //==============================================================================
-// missing dst operand or lds modifier
-
-buffer_load_dword off, s[8:11], s3
-// CHECK: error: missing dst operand or lds modifier
-// CHECK-NEXT:{{^}}buffer_load_dword off, s[8:11], s3
-// CHECK-NEXT:{{^}}^
-
-buffer_load_dword off, s[8:11], s3 offset:1
-// CHECK: error: missing dst operand or lds modifier
-// CHECK-NEXT:{{^}}buffer_load_dword off, s[8:11], s3 offset:1
-// CHECK-NEXT:{{^}}^
-
-//==============================================================================
 // missing message operation
 
 s_sendmsg sendmsg(MSG_SYSMSG)
@@ -1191,6 +1178,16 @@ v_add_f32_e64 v0, v1
 // CHECK-NEXT:{{^}}v_add_f32_e64 v0, v1
 // CHECK-NEXT:{{^}}^
 
+buffer_load_dword off, s[8:11], s3
+// CHECK: error: too few operands for instruction
+// CHECK-NEXT:{{^}}buffer_load_dword off, s[8:11], s3
+// CHECK-NEXT:{{^}}^
+
+buffer_load_dword off, s[8:11], s3 offset:1
+// CHECK: error: too few operands for instruction
+// CHECK-NEXT:{{^}}buffer_load_dword off, s[8:11], s3 offset:1
+// CHECK-NEXT:{{^}}^
+
 //==============================================================================
 // too large value for expcnt
 
index 4842dbe..b483ec5 100644 (file)
@@ -37,7 +37,7 @@ global_load_lds_dword v[2:3], off
 // GFX9ERR: error: instruction not supported on this GPU
 
 global_load_dword v[2:3], off
-// GFX9ERR: error: missing dst operand or lds modifier
+// GFX9ERR: error: too few operands for instruction
 
 scratch_load_dword v2, off, offset:256
-// GFX9ERR: error: missing dst operand or lds modifier
+// GFX9ERR: error: too few operands for instruction
index b9ad41e..76ef5d2 100644 (file)
@@ -179,15 +179,15 @@ v_add_i16 v5, 0.5, v2
 // CHECK-NEXT:{{^}}              ^
 
 //==============================================================================
-// missing dst operand or lds modifier
+// too few operands for instruction
 
 buffer_load_dword off, s[8:11], s3
-// CHECK: error: missing dst operand or lds modifier
+// CHECK: error: too few operands for instruction
 // CHECK-NEXT:{{^}}buffer_load_dword off, s[8:11], s3
 // CHECK-NEXT:{{^}}^
 
 buffer_load_dword off, s[8:11], s3 offset:1
-// CHECK: error: missing dst operand or lds modifier
+// CHECK: error: too few operands for instruction
 // CHECK-NEXT:{{^}}buffer_load_dword off, s[8:11], s3 offset:1
 // CHECK-NEXT:{{^}}^
 
index 7caecda..e267b1c 100644 (file)
@@ -862,7 +862,7 @@ buffer_store_lds_dword s[4:7], s8 offset:4 tfe lds
 // NOVI:   error: invalid operand for instruction
 
 buffer_load_dword off, s[8:11], s3
-// NOSICIVI: error: missing dst operand or lds modifier
+// NOSICIVI: error: too few operands for instruction
 
 buffer_load_dword off, s[8:11], s3 offset:1
-// NOSICIVI: error: missing dst operand or lds modifier
+// NOSICIVI: error: too few operands for instruction
index 843d3ae..0353f27 100644 (file)
@@ -8,53 +8,63 @@
 // CHECK: Matching formal operand class MCK_GR64 against actual operand at index 1 (Reg:r3): match success using generic matcher
 // CHECK: Matching formal operand class MCK_GR64 against actual operand at index 2 (Reg:r0): match success using generic matcher
 // CHECK: Matching formal operand class MCK_BDAddr32Disp20 against actual operand at index 3 (Mem:3): match success using generic matcher
-// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 4: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 4: actual operand index out of range
+// CHECK: Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 1 encodings with mnemonic 'llill'
 // CHECK: Trying to match opcode LLILL
 // CHECK: Matching formal operand class MCK_GR64 against actual operand at index 1 (Reg:r0): match success using generic matcher
 // CHECK: Matching formal operand class MCK_U16Imm against actual operand at index 2 (Imm:0): match success using generic matcher
-// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range
+// CHECK: Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 1 encodings with mnemonic 'lgr'
 // CHECK: Trying to match opcode LGR
 // CHECK: Matching formal operand class MCK_GR64 against actual operand at index 1 (Reg:r1): match success using generic matcher
 // CHECK: Matching formal operand class MCK_GR64 against actual operand at index 2 (Reg:r0): match success using generic matcher
-// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range
+// CHECK: Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 1 encodings with mnemonic 'lg'
 // CHECK: Trying to match opcode LG
 // CHECK: Matching formal operand class MCK_GR64 against actual operand at index 1 (Reg:r1): match success using generic matcher
 // CHECK: Matching formal operand class MCK_BDXAddr64Disp20 against actual operand at index 2 (Mem:16(r2)): match success using generic matcher
-// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range
+// CHECK: Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 1 encodings with mnemonic 'lg'
 // CHECK: Trying to match opcode LG
 // CHECK: Matching formal operand class MCK_GR64 against actual operand at index 1 (Reg:r1): match success using generic matcher
 // CHECK: Matching formal operand class MCK_BDXAddr64Disp20 against actual operand at index 2 (Mem:16(r2,r3)): match success using generic matcher
-// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range
+// CHECK: Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 1 encodings with mnemonic 'stmg'
 // CHECK: Trying to match opcode STMG
 // CHECK: Matching formal operand class MCK_GR64 against actual operand at index 1 (Reg:r13): match success using generic matcher
 // CHECK: Matching formal operand class MCK_GR64 against actual operand at index 2 (Reg:r15): match success using generic matcher
 // CHECK: Matching formal operand class MCK_BDAddr64Disp20 against actual operand at index 3 (Mem:104(r15)): match success using generic matcher
-// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 4: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 4: actual operand index out of range
+// CHECK: Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 1 encodings with mnemonic 'mvc'
 // CHECK: Trying to match opcode MVC
 // CHECK: Matching formal operand class MCK_BDLAddr64Disp12Len8 against actual operand at index 1 (Mem:184(8,r15)): match success using generic matcher
 // CHECK: Matching formal operand class MCK_BDAddr64Disp12 against actual operand at index 2 (Mem:8(r2)): match success using generic matcher
-// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range
+// CHECK: Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 1 encodings with mnemonic 'mvck'
 // CHECK: Trying to match opcode MVCK
 // CHECK: Matching formal operand class MCK_BDRAddr64Disp12 against actual operand at index 1 (Mem:0(r0,r1)): match success using generic matcher
 // CHECK: Matching formal operand class MCK_BDAddr64Disp12 against actual operand at index 2 (Mem:4095(r15)): match success using generic matcher
 // CHECK: Matching formal operand class MCK_GR64 against actual operand at index 3 (Reg:r2): match success using generic matcher
-// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 4: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 4: actual operand index out of range
+// CHECK: Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 1 encodings with mnemonic 'j'
 // CHECK: Trying to match opcode J
 // CHECK: Matching formal operand class MCK_PCRel16 against actual operand at index 1 (Imm:.Ltmp0+2): match success using generic matcher
-// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 2: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 2: actual operand index out of range
+// CHECK: Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 1 encodings with mnemonic 'brasl'
 // CHECK: Trying to match opcode BRASL
 // CHECK: Matching formal operand class MCK_GR64 against actual operand at index 1 (Reg:r14): match success using generic matcher
 // CHECK: Matching formal operand class MCK_PCRelTLS32 against actual operand at index 2 (ImmTLS:fun): match success using generic matcher
-// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range
+// CHECK: Opcode result: complete match, selecting this opcode
 // CHECK: .text
 // CHECK: sllg %r3, %r0, 3
 // CHECK: llill        %r0, 0
index 74f9211..f436fd2 100644 (file)
@@ -9,13 +9,15 @@
 // CHECK: Trying to match opcode PSHUFBrm
 // CHECK:   Matching formal operand class MCK_Mem128 against actual operand at index 1 (Memory: ModeSize=64,BaseReg=rip,Scale=1,Disp=CPI1_0): match success using generic matcher
 // CHECK:   Matching formal operand class MCK_FR16 against actual operand at index 2 (Reg:xmm1): match success using generic matcher
-// CHECK:   Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK:   Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range
+// CHECK:   Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 2 encodings with mnemonic 'sha1rnds4'
 // CHECK: Trying to match opcode SHA1RNDS4rri
 // CHECK:   Matching formal operand class MCK_ImmUnsignedi8 against actual operand at index 1 (Imm:1): match success using generic matcher
 // CHECK:   Matching formal operand class MCK_FR16 against actual operand at index 2 (Reg:xmm1): match success using generic matcher
 // CHECK:   Matching formal operand class MCK_FR16 against actual operand at index 3 (Reg:xmm2): match success using generic matcher
-// CHECK:   Matching formal operand class InvalidMatchClass against actual operand at index 4: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK:   Matching formal operand class InvalidMatchClass against actual operand at index 4: actual operand index out of range
+// CHECK:   Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 4 encodings with mnemonic 'pinsrw'
 // CHECK: Trying to match opcode MMX_PINSRWrr
 // CHECK:   Matching formal operand class MCK_ImmUnsignedi8 against actual operand at index 1 (Imm:3): match success using generic matcher
 // CHECK:   Matching formal operand class MCK_ImmUnsignedi8 against actual operand at index 1 (Imm:3): match success using generic matcher
 // CHECK:   Matching formal operand class MCK_GR32orGR64 against actual operand at index 2 (Reg:ecx): match success using generic matcher
 // CHECK:   Matching formal operand class MCK_FR16 against actual operand at index 3 (Reg:xmm5): match success using generic matcher
-// CHECK:   Matching formal operand class InvalidMatchClass against actual operand at index 4: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK:   Matching formal operand class InvalidMatchClass against actual operand at index 4: actual operand index out of range
+// CHECK:   Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 2 encodings with mnemonic 'crc32l'
 // CHECK: Trying to match opcode CRC32r32r32
 // CHECK:   Matching formal operand class MCK_GR32 against actual operand at index 1 (Memory: ModeSize=64,BaseReg=rbx,IndexReg=rcx,Scale=8,Disp=3735928559,SegReg=gs): Opcode result: multiple operand mismatches, ignoring this opcode
 // CHECK: Trying to match opcode CRC32r32m32
 // CHECK:   Matching formal operand class MCK_Mem32 against actual operand at index 1 (Memory: ModeSize=64,BaseReg=rbx,IndexReg=rcx,Scale=8,Disp=3735928559,SegReg=gs): match success using generic matcher
 // CHECK:   Matching formal operand class MCK_GR32 against actual operand at index 2 (Reg:ecx): match success using generic matcher
-// CHECK:   Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK:   Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range
+// CHECK:   Opcode result: complete match, selecting this opcode
 // CHECK: AsmMatcher: found 4 encodings with mnemonic 'punpcklbw'
 // CHECK: Trying to match opcode MMX_PUNPCKLBWrr
 // CHECK:   Matching formal operand class MCK_VR64 against actual operand at index 1 (Reg:mm0): match success using generic matcher
@@ -40,7 +44,8 @@
 // CHECK: Trying to match opcode MMX_PUNPCKLBWrm
 // CHECK:   Matching formal operand class MCK_VR64 against actual operand at index 1 (Reg:mm0): match success using generic matcher
 // CHECK:   Matching formal operand class MCK_Mem32 against actual operand at index 2 (Memory: ModeSize=64,Size=32,BaseReg=rsp,Scale=1): match success using generic matcher
-// CHECK:   Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range Opcode result: complete match, selecting this opcode
+// CHECK:   Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range
+// CHECK:   Opcode result: complete match, selecting this opcode
 
 pshufb    CPI1_0(%rip), %xmm1
 sha1rnds4 $1, %xmm1, %xmm2
index 852ef5a..d90b679 100644 (file)
@@ -3666,7 +3666,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
   OS << "      else\n";
   OS << "        DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \": \");\n";
   OS << "      if (ActualIdx >= Operands.size()) {\n";
-  OS << "        DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"actual operand index out of range \");\n";
+  OS << "        DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"actual operand "
+        "index out of range\\n\");\n";
   if (ReportMultipleNearMisses) {
     OS << "        bool ThisOperandValid = (Formal == " <<"InvalidMatchClass) || "
                                    "isSubclass(Formal, OptionalMatchClass);\n";
@@ -3690,12 +3691,21 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
     OS << "        }\n";
     OS << "        continue;\n";
   } else {
-    OS << "        OperandsValid = (Formal == InvalidMatchClass) || isSubclass(Formal, OptionalMatchClass);\n";
-    OS << "        if (!OperandsValid) ErrorInfo = ActualIdx;\n";
+    OS << "        if (Formal == InvalidMatchClass) {\n";
     if (HasOptionalOperands) {
-      OS << "        OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands
+      OS << "          OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands
          << ");\n";
     }
+    OS << "          break;\n";
+    OS << "        }\n";
+    OS << "        if (isSubclass(Formal, OptionalMatchClass)) {\n";
+    if (HasOptionalOperands) {
+      OS << "          OptionalOperandsMask.set(FormalIdx);\n";
+    }
+    OS << "          continue;\n";
+    OS << "        }\n";
+    OS << "        OperandsValid = false;\n";
+    OS << "        ErrorInfo = ActualIdx;\n";
     OS << "        break;\n";
   }
   OS << "      }\n";