[llvm] [TableGen][DecoderEmitter] Report all decoding conflicts (PR #157847)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 10 06:11:47 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-tablegen

Author: Rahul Joshi (jurahul)

<details>
<summary>Changes</summary>

Do not exit when the first decoding conflict is encountered. Instead record the conflict and continue to report any additional decoding conflicts and exit fatally after all instructions have been processed.

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


3 Files Affected:

- (modified) llvm/test/TableGen/FixedLenDecoderEmitter/conflict.td (+43-7) 
- (modified) llvm/test/TableGen/FixedLenDecoderEmitter/var-len-conflict-2.td (+7-9) 
- (modified) llvm/utils/TableGen/DecoderEmitter.cpp (+24-5) 


``````````diff
diff --git a/llvm/test/TableGen/FixedLenDecoderEmitter/conflict.td b/llvm/test/TableGen/FixedLenDecoderEmitter/conflict.td
index 853a68d22d1d9..e3666ebbf942a 100644
--- a/llvm/test/TableGen/FixedLenDecoderEmitter/conflict.td
+++ b/llvm/test/TableGen/FixedLenDecoderEmitter/conflict.td
@@ -9,27 +9,63 @@ def MyTarget : Target { let InstructionSet = MyTargetISA; }
 def R0 : Register<"r0"> { let Namespace = "MyTarget"; }
 def GPR32 : RegisterClass<"MyTarget", [i32], 32, (add R0)>;
 
+def X0 : Register<"x0"> { let Namespace = "MyTarget"; }
+def GPR64 : RegisterClass<"MyTarget", [i64], 64, (add X0)>;
+
 class I<dag OOps, dag IOps, list<dag> Pat>
   : Instruction {
   let Namespace = "MyTarget";
   let OutOperandList = OOps;
   let InOperandList = IOps;
   let Pattern = Pat;
+  let Size = 4;
   bits<32> Inst;
   bits<32> SoftFail;
 }
 
+// Assume there is a 2 bit encoding for the dst and src register.
 def A : I<(outs GPR32:$dst), (ins GPR32:$src1), []> {
-  let Size = 4;
-  let Inst{31...0} = 0;
+  bits<2> dst;
+  bits<2> src1;
+  let Inst{31...4} = 0;
+  let Inst{1...0} = dst;
+  let Inst{3...2} = src1;
 }
+
 def B : I<(outs GPR32:$dst), (ins GPR32:$src1), []> {
-  let Size = 4;
-  let Inst{31...0} = 0;
+  bits<2> dst;
+  bits<2> src1;
+  let Inst{31...4} = 0;
+  let Inst{1...0} = dst;
+  let Inst{3...2} = src1;
+}
+
+def C : I<(outs GPR64:$dst), (ins GPR64:$src1), []> {
+  bits<2> dst;
+  bits<2> src1;
+  let Inst{31...4} = 1;
+  let Inst{1...0} = dst;
+  let Inst{3...2} = src1;
 }
 
+def D : I<(outs GPR64:$dst), (ins GPR64:$src1), []> {
+  bits<2> dst;
+  bits<2> src1;
+  let Inst{31...4} = 1;
+  let Inst{1...0} = dst;
+  let Inst{3...2} = src1;
+}
+
+// CHECK: Decoding Conflict:
+// CHECK:     ................................
+// CHECK:     0000000000000000000000000000....
+// CHECK:     0000000000000000000000000000____  A
+// CHECK:     0000000000000000000000000000____  B
+
 // CHECK: Decoding Conflict:
 // CHECK:     ................................
-// CHECK:     00000000000000000000000000000000
-// CHECK:     00000000000000000000000000000000  A
-// CHECK:     00000000000000000000000000000000  B
+// CHECK:     0000000000000000000000000001....
+// CHECK:     0000000000000000000000000001____  C
+// CHECK:     0000000000000000000000000001____  D
+
+// CHECK: Decoding conflict encountered
diff --git a/llvm/test/TableGen/FixedLenDecoderEmitter/var-len-conflict-2.td b/llvm/test/TableGen/FixedLenDecoderEmitter/var-len-conflict-2.td
index 8a848a986ce24..7ca13b8debd9d 100644
--- a/llvm/test/TableGen/FixedLenDecoderEmitter/var-len-conflict-2.td
+++ b/llvm/test/TableGen/FixedLenDecoderEmitter/var-len-conflict-2.td
@@ -10,16 +10,14 @@ class I : Instruction {
 
 // Check pretty printing of decoding conflicts.
 
-// CHECK:      {{^}}Decoding Conflict:
-// CHECK-NEXT: {{^}}                    ........
-// CHECK-NEXT: {{^}}            ..............11
-// CHECK-NEXT: {{^}}            .......0......11
-// CHECK-NEXT: {{^}}            _______0______11  I16_0
-// CHECK-NEXT: {{^}}            _______0______11  I16_1
-// CHECK-NEXT: {{^}}    _______0_______0______11  I24_0
+// CHECK:      Decoding Conflict:
+// CHECK-NEXT:             ................
+// CHECK-NEXT:             ..............11
+// CHECK-NEXT:             .......0......11
+// CHECK-NEXT:             _______0______11  I16_0
+// CHECK-NEXT:             _______0______11  I16_1
+// CHECK-NEXT:     _______0_______0______11  I24_0
 
-def I8_0  : I { dag Inst = (descend (operand "$op", 6), 0b00); }
-def I8_1  : I { dag Inst = (descend (operand "$op", 6), 0b01); }
 def I16_0 : I { dag Inst = (descend (operand "$op2", 7), 0b0,
                                     (operand "$op", 6), 0b11); }
 def I16_1 : I { dag Inst = (descend (operand "$op2", 7), 0b0,
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 95e7408ea88c7..ce7734b04cb36 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -517,6 +517,9 @@ class FilterChooser {
   /// The "field value" here refers to the encoding bits in the filtered range.
   std::map<uint64_t, std::unique_ptr<const FilterChooser>> FilterChooserMap;
 
+  /// Set to true if decoding conflict was encountered.
+  bool HasConflict = false;
+
   struct Island {
     unsigned StartBit;
     unsigned NumBits;
@@ -600,18 +603,22 @@ class DecoderTableBuilder {
   ArrayRef<InstructionEncoding> Encodings;
   DecoderTableInfo &TableInfo;
 
+  bool HasConflict = false;
+
 public:
   DecoderTableBuilder(const CodeGenTarget &Target,
                       ArrayRef<InstructionEncoding> Encodings,
                       DecoderTableInfo &TableInfo)
       : Target(Target), Encodings(Encodings), TableInfo(TableInfo) {}
 
-  void buildTable(const FilterChooser &FC, unsigned BitWidth) const {
+  /// Returns true if a decoding conflict was encountered.
+  bool buildTable(const FilterChooser &FC, unsigned BitWidth) {
     // When specializing decoders per bit width, each decoder table will begin
     // with the bitwidth for that table.
     if (SpecializeDecodersPerBitwidth)
       TableInfo.Table.insertULEB128(BitWidth);
     emitTableEntries(FC);
+    return HasConflict;
   }
 
 private:
@@ -637,7 +644,7 @@ class DecoderTableBuilder {
 
   void emitSingletonTableEntry(const FilterChooser &FC) const;
 
-  void emitTableEntries(const FilterChooser &FC) const;
+  void emitTableEntries(const FilterChooser &FC);
 };
 
 } // end anonymous namespace
@@ -1592,7 +1599,7 @@ void FilterChooser::doFilter() {
   // Print out useful conflict information for postmortem analysis.
   errs() << "Decoding Conflict:\n";
   dump();
-  PrintFatalError("Decoding conflict encountered");
+  HasConflict = true;
 }
 
 void FilterChooser::dump() const {
@@ -1612,7 +1619,12 @@ void FilterChooser::dump() const {
   }
 }
 
-void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) const {
+void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) {
+  if (FC.HasConflict) {
+    HasConflict = true;
+    return;
+  }
+
   DecoderTable &Table = TableInfo.Table;
 
   // If there are other encodings that could match if those with all bits
@@ -2570,6 +2582,7 @@ template <typename T> constexpr uint32_t InsnBitWidth = 0;
   DecoderTableBuilder TableBuilder(Target, Encodings, TableInfo);
   unsigned OpcodeMask = 0;
 
+  bool HasConflict = false;
   for (const auto &[BitWidth, BWMap] : EncMap) {
     for (const auto &[Key, EncodingIDs] : BWMap) {
       auto [DecoderNamespace, HwModeID] = Key;
@@ -2585,7 +2598,10 @@ template <typename T> constexpr uint32_t InsnBitWidth = 0;
       //    across all decoder tables.
       //  - predicates are shared across all decoder tables.
       TableInfo.Table.clear();
-      TableBuilder.buildTable(FC, BitWidth);
+      HasConflict |= TableBuilder.buildTable(FC, BitWidth);
+      // Skip emitting table entries if a conflict has been detected.
+      if (HasConflict)
+        continue;
 
       // Print the table to the output stream.
       OpcodeMask |= emitTable(OS, TableInfo.Table, DecoderNamespace, HwModeID,
@@ -2600,6 +2616,9 @@ template <typename T> constexpr uint32_t InsnBitWidth = 0;
     }
   }
 
+  if (HasConflict)
+    PrintFatalError("Decoding conflict encountered");
+
   // Emit the decoder function for the last bucket. This will also emit the
   // single decoder function if SpecializeDecodersPerBitwidth = false.
   if (!SpecializeDecodersPerBitwidth)

``````````

</details>


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


More information about the llvm-commits mailing list