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 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/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index 95e7408ea88c7..8747d02ac892b 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> FilterChooserMap; + /// Set to true if decoding conflict was encountered. + bool HasConflict = false; + struct Island { unsigned StartBit; unsigned NumBits; @@ -559,6 +562,9 @@ class FilterChooser { return Encodings[EncodingIDs.back()].getBitWidth(); } + /// Returns true if any decoding conflicts were encountered. + bool hasConflict() const { return HasConflict; } + private: /// Applies the given filter to the set of encodings this FilterChooser /// works with, creating inferior FilterChoosers as necessary. @@ -684,6 +690,7 @@ void FilterChooser::applyFilter(const Filter &F) { // group of instructions whose segment values are variable. VariableFC = std::make_unique(Encodings, F.VariableIDs, FilterBits, *this); + HasConflict |= VariableFC->HasConflict; } // Otherwise, create sub choosers. @@ -695,9 +702,11 @@ void FilterChooser::applyFilter(const Filter &F) { // Delegates to an inferior filter chooser for further processing on this // category of instructions. - FilterChooserMap.try_emplace(FilterVal, std::make_unique( - Encodings, InferiorEncodingIDs, - InferiorFilterBits, *this)); + auto [It, _] = FilterChooserMap.try_emplace( + FilterVal, + std::make_unique(Encodings, InferiorEncodingIDs, + InferiorFilterBits, *this)); + HasConflict |= It->second->HasConflict; } } @@ -1592,7 +1601,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 { @@ -2570,12 +2579,17 @@ template 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; // Emit the decoder for this (namespace, hwmode, width) combination. FilterChooser FC(Encodings, EncodingIDs); + HasConflict |= FC.hasConflict(); + // Skip emitting table entries if a conflict has been detected. + if (HasConflict) + continue; // The decode table is cleared for each top level decoder function. The // predicates and decoders themselves, however, are shared across @@ -2600,6 +2614,9 @@ template 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)