[llvm] [TableGen][Decoder] Remove special case of single sub-op dag (PR #156175)

via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 30 05:21:49 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-arm

Author: Sergei Barannikov (s-barannikov)

<details>
<summary>Changes</summary>

If a custom operand has MIOperandInfo with >= 2 sub-operands, it is
required that either the operand or its sub-operands have a custom
decoder method (depending on usage). Require this for single sub-operand
operands as well, since there is no good reason not to.


---
Full diff: https://github.com/llvm/llvm-project/pull/156175.diff


8 Files Affected:

- (modified) llvm/lib/Target/ARC/ARCInstrFormats.td (-2) 
- (modified) llvm/lib/Target/ARC/ARCInstrInfo.td (+1-1) 
- (modified) llvm/lib/Target/ARM/ARMInstrInfo.td (-2) 
- (modified) llvm/lib/Target/ARM/ARMInstrNEON.td (-4) 
- (modified) llvm/lib/Target/Lanai/LanaiInstrInfo.td (+8-8) 
- (modified) llvm/lib/Target/PowerPC/PPCInstrFuture.td (+16-16) 
- (modified) llvm/test/TableGen/FixedLenDecoderEmitter/MultiOps.td (+34-12) 
- (modified) llvm/utils/TableGen/DecoderEmitter.cpp (+4-9) 


``````````diff
diff --git a/llvm/lib/Target/ARC/ARCInstrFormats.td b/llvm/lib/Target/ARC/ARCInstrFormats.td
index bd2ed00576177..0560bb1dc9661 100644
--- a/llvm/lib/Target/ARC/ARCInstrFormats.td
+++ b/llvm/lib/Target/ARC/ARCInstrFormats.td
@@ -964,12 +964,10 @@ class F16_OP_U7<bit i, string asmstr> :
 
 // Special types for different instruction operands.
 def ccond : Operand<i32> {
-  let MIOperandInfo = (ops i32imm);
   let PrintMethod = "printPredicateOperand";
 }
 
 def brccond : Operand<i32> {
-  let MIOperandInfo = (ops i32imm);
   let PrintMethod = "printBRCCPredicateOperand";
 }
 
diff --git a/llvm/lib/Target/ARC/ARCInstrInfo.td b/llvm/lib/Target/ARC/ARCInstrInfo.td
index f26b49119caba..8ff5f4a39ca7f 100644
--- a/llvm/lib/Target/ARC/ARCInstrInfo.td
+++ b/llvm/lib/Target/ARC/ARCInstrInfo.td
@@ -18,7 +18,7 @@ include "ARCInstrFormats.td"
 
 // Operand for printing out a condition code.
 let PrintMethod = "printCCOperand" in
-  def CCOp : PredicateOperand<i32, (ops i32imm), (ops)>;
+  def CCOp : PredicateOperand<i32, (ops), (ops)>;
 
 // The "u6" operand of a RRU6-type instruction
 let PrintMethod = "printU6" in {
diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td
index 4345f7a4a0ebc..a4d7a20305624 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -765,7 +765,6 @@ class MVEVectorIndexOperand<int NumLanes> : AsmOperandClass {
 class MVEVectorIndex<int NumLanes> : Operand<i32> {
   let PrintMethod = "printVectorIndex";
   let ParserMatchClass = MVEVectorIndexOperand<NumLanes>;
-  let MIOperandInfo = (ops i32imm);
 }
 
 // shift_imm: An integer that encodes a shift amount and the type of shift
@@ -1181,7 +1180,6 @@ def PostIdxImm8AsmOperand : AsmOperandClass { let Name = "PostIdxImm8"; }
 def postidx_imm8 : MemOperand {
   let PrintMethod = "printPostIdxImm8Operand";
   let ParserMatchClass = PostIdxImm8AsmOperand;
-  let MIOperandInfo = (ops i32imm);
 }
 
 // postidx_imm8s4 := +/- [0,1020]
diff --git a/llvm/lib/Target/ARM/ARMInstrNEON.td b/llvm/lib/Target/ARM/ARMInstrNEON.td
index 7485ef569445a..37f0103363b9a 100644
--- a/llvm/lib/Target/ARM/ARMInstrNEON.td
+++ b/llvm/lib/Target/ARM/ARMInstrNEON.td
@@ -95,28 +95,24 @@ def VectorIndex8 : Operand<i32>, ImmLeaf<i32, [{
 }]> {
   let ParserMatchClass = VectorIndex8Operand;
   let PrintMethod = "printVectorIndex";
-  let MIOperandInfo = (ops i32imm);
 }
 def VectorIndex16 : Operand<i32>, ImmLeaf<i32, [{
   return ((uint64_t)Imm) < 4;
 }]> {
   let ParserMatchClass = VectorIndex16Operand;
   let PrintMethod = "printVectorIndex";
-  let MIOperandInfo = (ops i32imm);
 }
 def VectorIndex32 : Operand<i32>, ImmLeaf<i32, [{
   return ((uint64_t)Imm) < 2;
 }]> {
   let ParserMatchClass = VectorIndex32Operand;
   let PrintMethod = "printVectorIndex";
-  let MIOperandInfo = (ops i32imm);
 }
 def VectorIndex64 : Operand<i32>, ImmLeaf<i32, [{
   return ((uint64_t)Imm) < 1;
 }]> {
   let ParserMatchClass = VectorIndex64Operand;
   let PrintMethod = "printVectorIndex";
-  let MIOperandInfo = (ops i32imm);
 }
 
 // Register list of one D register.
diff --git a/llvm/lib/Target/Lanai/LanaiInstrInfo.td b/llvm/lib/Target/Lanai/LanaiInstrInfo.td
index 1d968fa391c2a..5129de047f953 100644
--- a/llvm/lib/Target/Lanai/LanaiInstrInfo.td
+++ b/llvm/lib/Target/Lanai/LanaiInstrInfo.td
@@ -540,15 +540,15 @@ let E = 0 in {
     def LDBs_RR : LoadRR<"ld.b", sextloadi8, i32>;
 }
 
-def LDADDR : InstSLS<0x0, (outs GPR:$Rd), (ins MEMi:$src),
+def LDADDR : InstSLS<0x0, (outs GPR:$Rd), (ins (MEMi $offset):$src),
                      "ld\t$src, $Rd",
                      [(set (i32 GPR:$Rd), (load ADDRsls:$src))]>,
     Sched<[WriteLD]> {
-  bits<21> src;
+  bits<21> offset;
 
   let Itinerary = IIC_LD;
-  let msb = src{20-16};
-  let lsb = src{15-0};
+  let msb = offset{20-16};
+  let lsb = offset{15-0};
   let isReMaterializable = 1;
   let mayLoad = 1;
 }
@@ -639,15 +639,15 @@ let E = 0 in {
     def STB_RR : StoreRR<"st.b", truncstorei8, i32>;
 }
 
-def STADDR : InstSLS<0x1, (outs), (ins GPR:$Rd, MEMi:$dst),
+def STADDR : InstSLS<0x1, (outs), (ins GPR:$Rd, (MEMi $offset):$dst),
                      "st\t$Rd, $dst",
                      [(store (i32 GPR:$Rd), ADDRsls:$dst)]>,
     Sched<[WriteST]> {
-  bits<21> dst;
+  bits<21> offset;
 
   let Itinerary = IIC_ST;
-  let msb = dst{20-16};
-  let lsb = dst{15-0};
+  let msb = offset{20-16};
+  let lsb = offset{15-0};
   let mayStore = 1;
 }
 
diff --git a/llvm/lib/Target/PowerPC/PPCInstrFuture.td b/llvm/lib/Target/PowerPC/PPCInstrFuture.td
index 80fac18d5737f..9eef7332f573b 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrFuture.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrFuture.td
@@ -54,31 +54,31 @@ let Predicates = [IsISAFuture] in {
 let Predicates = [HasVSX, IsISAFuture] in {
   let mayLoad = 1 in {
     def LXVRL
-        : XX1Form_memOp<31, 525, (outs vsrc:$XT), (ins memr:$RA, g8rc:$RB),
-                        "lxvrl $XT, $RA, $RB", IIC_LdStLoad, []>;
+        : XX1Form_memOp<31, 525, (outs vsrc:$XT), (ins (memr $RA):$addr, g8rc:$RB),
+                        "lxvrl $XT, $addr, $RB", IIC_LdStLoad, []>;
     def LXVRLL
-        : XX1Form_memOp<31, 557, (outs vsrc:$XT), (ins memr:$RA, g8rc:$RB),
-                        "lxvrll $XT, $RA, $RB", IIC_LdStLoad, []>;
+        : XX1Form_memOp<31, 557, (outs vsrc:$XT), (ins (memr $RA):$addr, g8rc:$RB),
+                        "lxvrll $XT, $addr, $RB", IIC_LdStLoad, []>;
     def LXVPRL
-        : XForm_XTp5_XAB5<31, 589, (outs vsrprc:$XTp), (ins memr:$RA, g8rc:$RB),
-                          "lxvprl $XTp, $RA, $RB", IIC_LdStLFD, []>;
+        : XForm_XTp5_XAB5<31, 589, (outs vsrprc:$XTp), (ins (memr $RA):$addr, g8rc:$RB),
+                          "lxvprl $XTp, $addr, $RB", IIC_LdStLFD, []>;
     def LXVPRLL
-        : XForm_XTp5_XAB5<31, 621, (outs vsrprc:$XTp), (ins memr:$RA, g8rc:$RB),
-                          "lxvprll $XTp, $RA, $RB", IIC_LdStLFD, []>;
+        : XForm_XTp5_XAB5<31, 621, (outs vsrprc:$XTp), (ins (memr $RA):$addr, g8rc:$RB),
+                          "lxvprll $XTp, $addr, $RB", IIC_LdStLFD, []>;
   }
 
   let mayStore = 1 in {
     def STXVRL
-        : XX1Form_memOp<31, 653, (outs), (ins vsrc:$XT, memr:$RA, g8rc:$RB),
-                        "stxvrl $XT, $RA, $RB", IIC_LdStLoad, []>;
+        : XX1Form_memOp<31, 653, (outs), (ins vsrc:$XT, (memr $RA):$addr, g8rc:$RB),
+                        "stxvrl $XT, $addr, $RB", IIC_LdStLoad, []>;
     def STXVRLL
-        : XX1Form_memOp<31, 685, (outs), (ins vsrc:$XT, memr:$RA, g8rc:$RB),
-                        "stxvrll $XT, $RA, $RB", IIC_LdStLoad, []>;
+        : XX1Form_memOp<31, 685, (outs), (ins vsrc:$XT, (memr $RA):$addr, g8rc:$RB),
+                        "stxvrll $XT, $addr, $RB", IIC_LdStLoad, []>;
     def STXVPRL : XForm_XTp5_XAB5<31, 717, (outs),
-                                  (ins vsrprc:$XTp, memr:$RA, g8rc:$RB),
-                                  "stxvprl $XTp, $RA, $RB", IIC_LdStLFD, []>;
+                                  (ins vsrprc:$XTp, (memr $RA):$addr, g8rc:$RB),
+                                  "stxvprl $XTp, $addr, $RB", IIC_LdStLFD, []>;
     def STXVPRLL : XForm_XTp5_XAB5<31, 749, (outs),
-                                   (ins vsrprc:$XTp, memr:$RA, g8rc:$RB),
-                                   "stxvprll $XTp, $RA, $RB", IIC_LdStLFD, []>;
+                                   (ins vsrprc:$XTp, (memr $RA):$addr, g8rc:$RB),
+                                   "stxvprll $XTp, $addr, $RB", IIC_LdStLFD, []>;
   }
 }
diff --git a/llvm/test/TableGen/FixedLenDecoderEmitter/MultiOps.td b/llvm/test/TableGen/FixedLenDecoderEmitter/MultiOps.td
index d7263b69dd8f4..ef15b6b9a9001 100644
--- a/llvm/test/TableGen/FixedLenDecoderEmitter/MultiOps.td
+++ b/llvm/test/TableGen/FixedLenDecoderEmitter/MultiOps.td
@@ -12,39 +12,56 @@ def Reg : Register<"reg">;
 
 def Regs : RegisterClass<"foo", [i32], 0, (add Reg)>;
 
-def complex_nodec : Operand<i32> {
+def complex_nodec1 : Operand<i32> {
+  let MIOperandInfo = (ops Regs);
+}
+
+def complex_nodec2 : Operand<i32> {
   let MIOperandInfo = (ops Regs, Regs);
 }
 
-def complex_withdec : Operand<i32> {
+def complex_withdec1 : Operand<i32> {
+  let MIOperandInfo = (ops Regs);
+  let DecoderMethod = "DecodeComplex";
+}
+
+def complex_withdec2 : Operand<i32> {
   let MIOperandInfo = (ops Regs, Regs);
   let DecoderMethod = "DecodeComplex";
 }
 
 class ArchInstr : Instruction {
-  let Size = 1;
-  bits<8> Inst;
+  let Size = 2;
+  bits<16> Inst;
 }
 
 // This definition is broken in both directions:
 // 1. Uses a complex operand without a decoder, and without named sub-ops.
 // 2. Uses a complex operand with named sub-ops, but with a decoder as well.
 
-// CHECK: error: DecoderEmitter: operand "r1c" uses MIOperandInfo with multiple ops, but doesn't have a custom decoder!
+// CHECK: error: DecoderEmitter: operand "r1c" has non-empty MIOperandInfo, but doesn't have a custom decoder!
 // CHECK: note: Dumping record for previous error:
-// CHECK: error: DecoderEmitter: operand "r1ab" has type "complex_withdec" with a custom DecoderMethod, but also named sub-operands.
+// CHECK: error: DecoderEmitter: operand "r2b" has non-empty MIOperandInfo, but doesn't have a custom decoder!
+// CHECK: note: Dumping record for previous error:
+// CHECK: error: DecoderEmitter: operand "r1" has type "complex_withdec2" with a custom DecoderMethod, but also named sub-operands.
+// CHECK: error: DecoderEmitter: operand "r2" has type "complex_withdec1" with a custom DecoderMethod, but also named sub-operands.
 def foo1 : ArchInstr {
   bits<2> r1a;
   bits<2> r1b;
   bits<2> r1c;
+  bits<2> r2a;
+  bits<2> r2b;
 
   let Inst{1-0} = r1a;
   let Inst{3-2} = r1b;
   let Inst{5-4} = r1c;
-  let Inst{7-6} = 0b00;
+  let Inst{7-6} = r2a;
+  let Inst{9-8} = r2b;
+  let Inst{11-10} = 0b00;
 
-  let OutOperandList = (outs complex_nodec:$r1c);
-  let InOperandList = (ins (complex_withdec $r1a, $r1b):$r1ab);
+  let OutOperandList = (outs complex_nodec2:$r1c, complex_nodec1:$r2b);
+  let InOperandList = (ins (complex_withdec2 $r1a, $r1b):$r1,
+                           (complex_withdec1 $r2a):$r2);
 }
 
 // This definition has no errors.
@@ -52,12 +69,17 @@ def foo2 : ArchInstr {
   bits<2> r2a;
   bits<2> r2b;
   bits<2> r2c;
+  bits<2> r1a;
+  bits<2> r1b;
 
   let Inst{1-0} = r2a;
   let Inst{3-2} = r2b;
   let Inst{5-4} = r2c;
-  let Inst{7-6} = 0b01;
+  let Inst{7-6} = r1a;
+  let Inst{9-8} = r1b;
+  let Inst{11-10} = 0b01;
 
-  let OutOperandList = (outs complex_withdec:$r2c);
-  let InOperandList = (ins (complex_nodec $r2a, $r2b):$r2ab);
+  let OutOperandList = (outs complex_withdec2:$r2c, complex_withdec1:$r1b);
+  let InOperandList = (ins (complex_nodec2 $r2a, $r2b):$r2,
+                           (complex_nodec1 $r1a):$r1);
 }
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index f1db0368d0988..451e831d2dd5f 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -2023,17 +2023,12 @@ void InstructionEncoding::parseFixedLenOperands(const BitsInit &Bits) {
     // Otherwise, if we have an operand with sub-operands, but they aren't
     // named...
     if (SubOps && OpInfo.Decoder.empty()) {
-      // If it's a single sub-operand, and no custom decoder, use the decoder
-      // from the one sub-operand.
-      if (SubOps->getNumArgs() == 1)
-        OpInfo = getOpInfo(cast<DefInit>(SubOps->getArg(0))->getDef());
-
-      // If we have multiple sub-ops, there'd better have a custom
-      // decoder. (Otherwise we don't know how to populate them properly...)
-      if (SubOps->getNumArgs() > 1) {
+      // If we have sub-ops, we'd better have a custom decoder.
+      // (Otherwise we don't know how to populate them properly...)
+      if (SubOps->getNumArgs()) {
         PrintError(EncodingDef,
                    "DecoderEmitter: operand \"" + OpName +
-                       "\" uses MIOperandInfo with multiple ops, but doesn't "
+                       "\" has non-empty MIOperandInfo, but doesn't "
                        "have a custom decoder!");
         debugDumpRecord(*EncodingDef);
         continue;

``````````

</details>


https://github.com/llvm/llvm-project/pull/156175


More information about the llvm-commits mailing list