[NFC] Move SymCache to its own header

This commit is contained in:
Andrew Lenharth 2022-02-24 16:23:32 -06:00
parent a57918d0e7
commit 2755c0630c
13 changed files with 122 additions and 94 deletions

View File

@ -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<Item> symbolCache;
// Construct a string key with embedded null. StringMapImpl::FindKey uses
// explicit lengths and stores keylength, rather than relying on null
// characters.
SmallVector<char> mkInnerKey(StringRef mod, StringRef name) const {
assert(!mod.contains(0) && !name.contains(0) &&
"Null character in identifier");
SmallVector<char> key;
key.append(mod.begin(), mod.end());
key.push_back(0);
key.append(name.begin(), name.end());
return key;
}
};
} // namespace hw
} // namespace circt

View File

@ -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<mlir::Attribute, Item> symbolCache;
};
} // namespace hw
} // namespace circt
#endif // CIRCT_DIALECT_HW_SYMCACHE_H

View File

@ -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"

View File

@ -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<StringAttr>(
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<InterfaceInstanceOp>(op))
if (auto attr = instOp.sym_nameAttr())
symbolCache.addDefinition(moduleOp.getNameAttr(), attr.getValue(),
op);
symbolCache.addDefinition(moduleOp.getNameAttr(), attr, op);
if (isa<BindOp>(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<FlatSymbolRefAttr>())
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<FlatSymbolRefAttr>())
symbolCache.addDefinition(moduleOp.getNameAttr(), sym.getValue(),
symbolCache.addDefinition(moduleOp.getNameAttr(), sym.getAttr(),
moduleOp, p + numArgs);
};

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "circt/Dialect/HW/HWSymCache.h"
#include "circt/InitAllTranslations.h"
#include "mlir/Support/LogicalResult.h"
#include "mlir/Translation.h"