diff --git a/include/llvm-dialects/TableGen/Dialects.h b/include/llvm-dialects/TableGen/Dialects.h index f4b6067..2328d51 100644 --- a/include/llvm-dialects/TableGen/Dialects.h +++ b/include/llvm-dialects/TableGen/Dialects.h @@ -21,6 +21,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringMap.h" namespace llvm { class DagInit; @@ -47,10 +48,11 @@ class GenDialect { std::string cppNamespace; std::vector types; std::vector opClasses; + llvm::StringMap operationCounts; std::vector> operations; public: - void finalize(); + void finalize(llvm::raw_ostream &errs); llvm::ArrayRef> attribute_lists() const { return m_attributeLists; diff --git a/lib/TableGen/Dialects.cpp b/lib/TableGen/Dialects.cpp index 6339066..3a9a4dd 100644 --- a/lib/TableGen/Dialects.cpp +++ b/lib/TableGen/Dialects.cpp @@ -28,7 +28,7 @@ using namespace llvm; using namespace llvm_dialects; -void GenDialect::finalize() { +void GenDialect::finalize(raw_ostream &errs) { // Build the list of different attribute lists. auto traitLess = [](Trait *lhs, Trait *rhs) { return lhs->getName() < rhs->getName(); @@ -41,6 +41,18 @@ void GenDialect::finalize() { std::vector traitOperations; + bool hasDuplicates = false; + for (const auto &[op, count] : operationCounts) { + if (count != 1) { + errs << "Found op with non-unique mnemonic: " << op << '\n'; + hasDuplicates = true; + } + } + + if (hasDuplicates) + report_fatal_error( + "Aborting dialect generation since non-unique mnemonics were found!"); + for (const auto &op : operations) { if (op->traits.empty()) continue; @@ -219,5 +231,5 @@ void GenDialectsContext::init(RecordKeeper &records, } for (auto &dialectEntry : m_dialects) - dialectEntry.second->finalize(); + dialectEntry.second->finalize(llvm::errs()); } diff --git a/lib/TableGen/Operations.cpp b/lib/TableGen/Operations.cpp index dbbc502..0ee493a 100644 --- a/lib/TableGen/Operations.cpp +++ b/lib/TableGen/Operations.cpp @@ -447,6 +447,7 @@ bool Operation::parse(raw_ostream &errs, GenDialectsContext *context, op->m_builders.push_back(std::move(builder)); + ++dialect->operationCounts[op->mnemonic]; dialect->operations.push_back(std::move(op)); return true; diff --git a/test/tablegen/duplicate-ops.td b/test/tablegen/duplicate-ops.td new file mode 100644 index 0000000..101c505 --- /dev/null +++ b/test/tablegen/duplicate-ops.td @@ -0,0 +1,45 @@ +// RUN: not --crash llvm-dialects-tblgen -gen-dialect-defs -dialect=dups -I%S/../../include %s 2>&1 | FileCheck --check-prefixes=CHECK %s + +// CHECK: Found op with non-unique mnemonic: duplicate.op +// CHECK-NEXT: Found op with non-unique mnemonic: duplicate.op.1 +// CHECK-NEXT: LLVM ERROR: Aborting dialect generation since non-unique mnemonics were found! + +include "llvm-dialects/Dialect/Dialect.td" + +def TestDialect : Dialect { + let name = "dups"; + let cppNamespace = "dups"; +} + +class TestOp traits_> + : Op; + +def DuplicateOp : TestOp<"duplicate.op", + []> { + let results = (outs); + let arguments = (ins); +} + +def DuplicateOp1 : TestOp<"duplicate.op", + []> { + let results = (outs); + let arguments = (ins); +} + +def DuplicateOp2 : TestOp<"duplicate.op.1", + []> { + let results = (outs); + let arguments = (ins); +} + +def DuplicateOp3 : TestOp<"duplicate.op.1", + []> { + let results = (outs); + let arguments = (ins); +} + +def UniqueOp : TestOp<"unique.op", + []> { + let results = (outs); + let arguments = (ins); +}