diff --git a/include/circt/Dialect/HW/HWOps.h b/include/circt/Dialect/HW/HWOps.h index 11f146dd7f..528116f10a 100644 --- a/include/circt/Dialect/HW/HWOps.h +++ b/include/circt/Dialect/HW/HWOps.h @@ -170,95 +170,6 @@ StringAttr getArgSym(Operation *op, unsigned i); /// argument. StringAttr getResultSym(Operation *op, unsigned i); -/// This stores lookup tables to make manipulating and working with the IR more -/// efficient. There are two phases to this object: the "building" phase in -/// which it is "write only" and then the "using" phase which is read-only (and -/// thus can be used by multiple threads). The -/// "freeze" method transitions between the two states. -class SymbolCache { -public: - class Item { - public: - Item(Operation *op) : op(op), port(~0ULL) {} - Item(Operation *op, size_t port) : op(op), port(port) {} - bool hasPort() const { return port != ~0ULL; } - Operation *getOp() const { return op; } - size_t getPort() const { return port; } - - private: - Operation *op; - size_t port; - }; - - /// In the building phase, add symbols. - void addDefinition(StringAttr symbol, Operation *op) { - assert(!isFrozen && "cannot mutate a frozen cache"); - symbolCache.try_emplace(symbol.getValue(), op, ~0ULL); - } - - // Add inner names, which might be ports - void addDefinition(StringAttr symbol, StringRef name, Operation *op, - size_t port = ~0ULL) { - assert(!isFrozen && "cannot mutate a frozen cache"); - auto key = mkInnerKey(symbol.getValue(), name); - symbolCache.try_emplace(StringRef(key.data(), key.size()), op, port); - } - - /// Mark the cache as frozen, which allows it to be shared across threads. - void freeze() { isFrozen = true; } - - Operation *getDefinition(StringRef symbol) const { - assert(isFrozen && "cannot read from this cache until it is frozen"); - auto it = symbolCache.find(symbol); - if (it == symbolCache.end()) - return nullptr; - assert(!it->second.hasPort() && "Module names should never be ports"); - return it->second.getOp(); - } - - Operation *getDefinition(StringAttr symbol) const { - return getDefinition(symbol.getValue()); - } - - Operation *getDefinition(FlatSymbolRefAttr symbol) const { - return getDefinition(symbol.getValue()); - } - - Item getDefinition(StringRef symbol, StringRef name) const { - assert(isFrozen && "cannot read from this cache until it is frozen"); - auto key = mkInnerKey(symbol, name); - auto it = symbolCache.find(StringRef(key.data(), key.size())); - return it == symbolCache.end() ? Item{nullptr, ~0ULL} : it->second; - } - - Item getDefinition(StringAttr symbol, StringAttr name) const { - return getDefinition(symbol.getValue(), name.getValue()); - } - -private: - bool isFrozen = false; - - /// This stores a lookup table from symbol attribute to the operation - /// (hw.module, hw.instance, etc) that defines it. - /// TODO: It is super annoying that symbols are *defined* as StringAttr, but - /// are then referenced as FlatSymbolRefAttr. Why can't we have nice - /// pointer uniqued things?? :-( - llvm::StringMap symbolCache; - - // Construct a string key with embedded null. StringMapImpl::FindKey uses - // explicit lengths and stores keylength, rather than relying on null - // characters. - SmallVector mkInnerKey(StringRef mod, StringRef name) const { - assert(!mod.contains(0) && !name.contains(0) && - "Null character in identifier"); - SmallVector key; - key.append(mod.begin(), mod.end()); - key.push_back(0); - key.append(name.begin(), name.end()); - return key; - } -}; - } // namespace hw } // namespace circt diff --git a/include/circt/Dialect/HW/HWSymCache.h b/include/circt/Dialect/HW/HWSymCache.h new file mode 100644 index 0000000000..d7ef4492e7 --- /dev/null +++ b/include/circt/Dialect/HW/HWSymCache.h @@ -0,0 +1,108 @@ +//===- HWSymCache.h - Declare Symbol Cache ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares a Symbol Cache. +// +//===----------------------------------------------------------------------===// + +#ifndef CIRCT_DIALECT_HW_SYMCACHE_H +#define CIRCT_DIALECT_HW_SYMCACHE_H + +#include "circt/Dialect/HW/HWAttributes.h" + +namespace circt { +namespace hw { + +/// This stores lookup tables to make manipulating and working with the IR more +/// efficient. There are two phases to this object: the "building" phase in +/// which it is "write only" and then the "using" phase which is read-only (and +/// thus can be used by multiple threads). The +/// "freeze" method transitions between the two states. +class SymbolCache { +public: + class Item { + public: + Item(mlir::Operation *op) : op(op), port(~0ULL) {} + Item(mlir::Operation *op, size_t port) : op(op), port(port) {} + bool hasPort() const { return port != ~0ULL; } + mlir::Operation *getOp() const { return op; } + size_t getPort() const { return port; } + + private: + mlir::Operation *op; + size_t port; + }; + + /// In the building phase, add symbols. + void addDefinition(mlir::StringAttr symbol, mlir::Operation *op) { + assert(!isFrozen && "cannot mutate a frozen cache"); + symbolCache.try_emplace(symbol, op, ~0ULL); + } + + // Add inner names, which might be ports + void addDefinition(mlir::StringAttr modSymbol, mlir::StringAttr name, + mlir::Operation *op, size_t port = ~0ULL) { + assert(!isFrozen && "cannot mutate a frozen cache"); + auto key = InnerRefAttr::get(modSymbol.getContext(), modSymbol, name); + symbolCache.try_emplace(key, op, port); + } + + // Add inner names, which might be ports + void addDefinition(InnerRefAttr name, mlir::Operation *op, + size_t port = ~0ULL) { + assert(!isFrozen && "cannot mutate a frozen cache"); + symbolCache.try_emplace(name, op, port); + } + + /// Mark the cache as frozen, which allows it to be shared across threads. + void freeze() { isFrozen = true; } + + mlir::Operation *getDefinition(mlir::StringAttr symbol) const { + return lookup(symbol); + } + + mlir::Operation *getDefinition(mlir::FlatSymbolRefAttr symbol) const { + return lookup(symbol.getAttr()); + } + + Item getDefinition(mlir::StringAttr modSymbol, mlir::StringAttr name) const { + return lookup(InnerRefAttr::get(modSymbol.getContext(), modSymbol, name)); + } + + Item getDefinition(InnerRefAttr name) const { return lookup(name); } + +private: + Item lookup(InnerRefAttr attr) const { + assert(isFrozen && "cannot read from this cache until it is frozen"); + auto it = symbolCache.find(attr); + return it == symbolCache.end() ? Item{nullptr, ~0ULL} : it->second; + } + + mlir::Operation *lookup(mlir::StringAttr attr) const { + assert(isFrozen && "cannot read from this cache until it is frozen"); + auto it = symbolCache.find(attr); + if (it == symbolCache.end()) + return nullptr; + assert(!it->second.hasPort() && "Module names should never be ports"); + return it->second.getOp(); + } + + bool isFrozen = false; + + /// This stores a lookup table from symbol attribute to the operation + /// (hw.module, hw.instance, etc) that defines it. + /// TODO: It is super annoying that symbols are *defined* as StringAttr, but + /// are then referenced as FlatSymbolRefAttr. Why can't we have nice + /// pointer uniqued things?? :-( + llvm::DenseMap symbolCache; +}; + +} // namespace hw +} // namespace circt + +#endif // CIRCT_DIALECT_HW_SYMCACHE_H diff --git a/lib/CAPI/Dialect/MSFT.cpp b/lib/CAPI/Dialect/MSFT.cpp index 82f85f2a72..2e426738bd 100644 --- a/lib/CAPI/Dialect/MSFT.cpp +++ b/lib/CAPI/Dialect/MSFT.cpp @@ -3,6 +3,7 @@ //===----------------------------------------------------------------------===// #include "circt-c/Dialect/MSFT.h" +#include "circt/Dialect/HW/HWSymCache.h" #include "circt/Dialect/MSFT/DeviceDB.h" #include "circt/Dialect/MSFT/ExportTcl.h" #include "circt/Dialect/MSFT/MSFTAttributes.h" diff --git a/lib/Conversion/ExportVerilog/ExportVerilog.cpp b/lib/Conversion/ExportVerilog/ExportVerilog.cpp index 15aa036d6d..fd0a520f63 100644 --- a/lib/Conversion/ExportVerilog/ExportVerilog.cpp +++ b/lib/Conversion/ExportVerilog/ExportVerilog.cpp @@ -4120,14 +4120,13 @@ void SharedEmitterState::gatherFiles(bool separateModules) { // Populate the symbolCache with all operations that can define a symbol. if (auto name = op->getAttrOfType( hw::InnerName::getInnerNameAttrName())) - symbolCache.addDefinition(moduleOp.getNameAttr(), name.getValue(), op); + symbolCache.addDefinition(moduleOp.getNameAttr(), name, op); // HACK: This is to make interface-related operations work as they are at // the moment, with names being stored in `sym_name` instead of // `inner_sym`. if (auto instOp = dyn_cast(op)) if (auto attr = instOp.sym_nameAttr()) - symbolCache.addDefinition(moduleOp.getNameAttr(), attr.getValue(), - op); + symbolCache.addDefinition(moduleOp.getNameAttr(), attr, op); if (isa(op)) modulesContainingBinds.insert(moduleOp); }); @@ -4138,12 +4137,12 @@ void SharedEmitterState::gatherFiles(bool separateModules) { for (size_t p = 0; p != numArgs; ++p) for (NamedAttribute argAttr : moduleOp.getArgAttrs(p)) if (auto sym = argAttr.getValue().dyn_cast()) - symbolCache.addDefinition(moduleOp.getNameAttr(), sym.getValue(), + symbolCache.addDefinition(moduleOp.getNameAttr(), sym.getAttr(), moduleOp, p); for (size_t p = 0, e = moduleOp.getNumResults(); p != e; ++p) for (NamedAttribute resultAttr : moduleOp.getResultAttrs(p)) if (auto sym = resultAttr.getValue().dyn_cast()) - symbolCache.addDefinition(moduleOp.getNameAttr(), sym.getValue(), + symbolCache.addDefinition(moduleOp.getNameAttr(), sym.getAttr(), moduleOp, p + numArgs); }; diff --git a/lib/Conversion/ExportVerilog/ExportVerilogInternals.h b/lib/Conversion/ExportVerilog/ExportVerilogInternals.h index ed03ea0451..2f2a6037b6 100644 --- a/lib/Conversion/ExportVerilog/ExportVerilogInternals.h +++ b/lib/Conversion/ExportVerilog/ExportVerilogInternals.h @@ -10,6 +10,7 @@ #define CONVERSION_EXPORTVERILOG_EXPORTVERILOGINTERNAL_H #include "circt/Dialect/HW/HWOps.h" +#include "circt/Dialect/HW/HWSymCache.h" #include "circt/Dialect/SV/SVOps.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallPtrSet.h" diff --git a/lib/Dialect/FIRRTL/Transforms/GrandCentralTaps.cpp b/lib/Dialect/FIRRTL/Transforms/GrandCentralTaps.cpp index b0f342b49d..3f65e468ae 100644 --- a/lib/Dialect/FIRRTL/Transforms/GrandCentralTaps.cpp +++ b/lib/Dialect/FIRRTL/Transforms/GrandCentralTaps.cpp @@ -21,6 +21,7 @@ #include "circt/Dialect/FIRRTL/Passes.h" #include "circt/Dialect/HW/HWAttributes.h" #include "circt/Dialect/HW/HWOps.h" +#include "circt/Dialect/HW/HWSymCache.h" #include "circt/Dialect/SV/SVOps.h" #include "mlir/IR/ImplicitLocOpBuilder.h" #include "llvm/ADT/STLExtras.h" diff --git a/lib/Dialect/HW/HWOps.cpp b/lib/Dialect/HW/HWOps.cpp index 472f5b4bf4..1bb17bfc68 100644 --- a/lib/Dialect/HW/HWOps.cpp +++ b/lib/Dialect/HW/HWOps.cpp @@ -14,6 +14,7 @@ #include "circt/Dialect/Comb/CombOps.h" #include "circt/Dialect/FIRRTL/FIRRTLOps.h" #include "circt/Dialect/HW/HWAttributes.h" +#include "circt/Dialect/HW/HWSymCache.h" #include "circt/Dialect/HW/HWVisitors.h" #include "circt/Dialect/HW/ModuleImplementation.h" #include "mlir/IR/Builders.h" diff --git a/lib/Dialect/HW/HWTypes.cpp b/lib/Dialect/HW/HWTypes.cpp index 876c3b32a0..b621ab7b57 100644 --- a/lib/Dialect/HW/HWTypes.cpp +++ b/lib/Dialect/HW/HWTypes.cpp @@ -14,6 +14,7 @@ #include "circt/Dialect/HW/HWAttributes.h" #include "circt/Dialect/HW/HWDialect.h" #include "circt/Dialect/HW/HWOps.h" +#include "circt/Dialect/HW/HWSymCache.h" #include "circt/Support/LLVM.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinTypes.h" diff --git a/lib/Dialect/MSFT/ExportQuartusTcl.cpp b/lib/Dialect/MSFT/ExportQuartusTcl.cpp index 3a7c8c6e58..12d3d47889 100644 --- a/lib/Dialect/MSFT/ExportQuartusTcl.cpp +++ b/lib/Dialect/MSFT/ExportQuartusTcl.cpp @@ -12,6 +12,7 @@ #include "circt/Dialect/HW/HWAttributes.h" #include "circt/Dialect/HW/HWOps.h" +#include "circt/Dialect/HW/HWSymCache.h" #include "circt/Dialect/HW/HWTypes.h" #include "circt/Dialect/MSFT/DeviceDB.h" #include "circt/Dialect/MSFT/ExportTcl.h" diff --git a/lib/Dialect/MSFT/MSFTPasses.cpp b/lib/Dialect/MSFT/MSFTPasses.cpp index e2b67a27a4..4fb10f0f21 100644 --- a/lib/Dialect/MSFT/MSFTPasses.cpp +++ b/lib/Dialect/MSFT/MSFTPasses.cpp @@ -8,6 +8,7 @@ #include "circt/Dialect/HW/HWAttributes.h" #include "circt/Dialect/HW/HWOps.h" +#include "circt/Dialect/HW/HWSymCache.h" #include "circt/Dialect/HW/HWTypes.h" #include "circt/Dialect/MSFT/ExportTcl.h" #include "circt/Dialect/MSFT/MSFTDialect.h" diff --git a/lib/Dialect/SV/SVOps.cpp b/lib/Dialect/SV/SVOps.cpp index 1168d8d82f..62355787ab 100644 --- a/lib/Dialect/SV/SVOps.cpp +++ b/lib/Dialect/SV/SVOps.cpp @@ -14,6 +14,7 @@ #include "circt/Dialect/Comb/CombOps.h" #include "circt/Dialect/HW/HWAttributes.h" #include "circt/Dialect/HW/HWOps.h" +#include "circt/Dialect/HW/HWSymCache.h" #include "circt/Dialect/HW/HWTypes.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinTypes.h" diff --git a/lib/Dialect/SV/Transforms/SVExtractTestCode.cpp b/lib/Dialect/SV/Transforms/SVExtractTestCode.cpp index 435aff63cf..f83f6aa47b 100644 --- a/lib/Dialect/SV/Transforms/SVExtractTestCode.cpp +++ b/lib/Dialect/SV/Transforms/SVExtractTestCode.cpp @@ -16,6 +16,7 @@ #include "PassDetail.h" #include "circt/Dialect/HW/HWAttributes.h" #include "circt/Dialect/HW/HWOps.h" +#include "circt/Dialect/HW/HWSymCache.h" #include "circt/Dialect/SV/SVPasses.h" #include "mlir/IR/BlockAndValueMapping.h" #include "mlir/IR/Builders.h" diff --git a/tools/circt-translate/circt-translate.cpp b/tools/circt-translate/circt-translate.cpp index 8640cdf91a..87ab0158ec 100644 --- a/tools/circt-translate/circt-translate.cpp +++ b/tools/circt-translate/circt-translate.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "circt/Dialect/HW/HWSymCache.h" #include "circt/InitAllTranslations.h" #include "mlir/Support/LogicalResult.h" #include "mlir/Translation.h"