[FIRRTL] Add helpers for the implementation of FIRRTL instance-like ops (#6484)

This commit is contained in:
Nandor Licker 2023-12-04 20:12:00 +02:00 committed by GitHub
parent e6b326ea49
commit 79baf6c364
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 183 additions and 119 deletions

View File

@ -0,0 +1,33 @@
//===- FIRRTLInstanceImplementation.h - Instance-like utilities -*- 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 provides utility functions for implementing FIRRTL instance-like
// operations, in particular, parsing, and printing common to instance-like
// operations.
//
//===----------------------------------------------------------------------===//
#ifndef CIRCT_DIALECT_FIRRTL_FIRRTLINSTANCEIMPLEMENTATION_H
#define CIRCT_DIALECT_FIRRTL_FIRRTLINSTANCEIMPLEMENTATION_H
#include "circt/Support/LLVM.h"
namespace circt {
namespace firrtl {
namespace instance_like_impl {
/// Verify that the instance refers to a valid FIRRTL module.
LogicalResult verifyReferencedModule(Operation *instanceOp,
SymbolTableCollection &symbolTable,
mlir::FlatSymbolRefAttr moduleName);
} // namespace instance_like_impl
} // namespace firrtl
} // namespace circt
#endif // CIRCT_DIALECT_FIRRTL_FIRRTLINSTANCEIMPLEMENTATION_H

View File

@ -1,4 +1,4 @@
//===- InstanceImplementation.h - Instance-like Op utilities ----*- C++ -*-===//
//===- HWInstanceImplementation.h - Instance-like Op utilities --*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
#ifndef CIRCT_DIALECT_HW_INSTANCEIMPLEMENTATION_H
#define CIRCT_DIALECT_HW_INSTANCEIMPLEMENTATION_H
#ifndef CIRCT_DIALECT_HW_HWINSTANCEIMPLEMENTATION_H
#define CIRCT_DIALECT_HW_HWINSTANCEIMPLEMENTATION_H
#include "circt/Dialect/HW/PortImplementation.h"
#include "circt/Support/LLVM.h"
@ -105,4 +105,4 @@ SmallVector<PortInfo> getPortList(Operation *instanceOp);
} // namespace hw
} // namespace circt
#endif // CIRCT_DIALECT_HW_INSTANCEIMPLEMENTATION_H
#endif // CIRCT_DIALECT_HW_HWINSTANCEIMPLEMENTATION_H

View File

@ -13,9 +13,9 @@
#ifndef CIRCT_DIALECT_HW_HWOPINTERFACES_H
#define CIRCT_DIALECT_HW_HWOPINTERFACES_H
#include "circt/Dialect/HW/HWInstanceImplementation.h"
#include "circt/Dialect/HW/HWTypes.h"
#include "circt/Dialect/HW/InnerSymbolTable.h"
#include "circt/Dialect/HW/InstanceImplementation.h"
#include "circt/Support/InstanceGraphInterface.h"
#include "circt/Support/LLVM.h"
#include "mlir/IR/OpDefinition.h"

View File

@ -13,8 +13,8 @@
#ifndef CIRCT_DIALECT_SYSTEMC_SYSTEMCOPS_H
#define CIRCT_DIALECT_SYSTEMC_SYSTEMCOPS_H
#include "circt/Dialect/HW/HWInstanceImplementation.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/HW/InstanceImplementation.h"
#include "circt/Dialect/SystemC/SystemCAttributes.h"
#include "circt/Dialect/SystemC/SystemCDialect.h"
#include "circt/Dialect/SystemC/SystemCOpInterfaces.h"

View File

@ -8,6 +8,7 @@ set(CIRCT_FIRRTL_Sources
FIRRTLFieldSource.cpp
FIRRTLFolds.cpp
FIRRTLInstanceGraph.cpp
FIRRTLInstanceImplementation.cpp
FIRRTLOpInterfaces.cpp
FIRRTLOps.cpp
FIRRTLTypes.cpp

View File

@ -0,0 +1,137 @@
//===- FIRRTLInstanceImplementation.cpp - Utilities for instance-like ops -===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "circt/Dialect/FIRRTL/FIRRTLInstanceImplementation.h"
#include "circt/Dialect/FIRRTL/FIRRTLOps.h"
using namespace circt;
using namespace circt::firrtl;
LogicalResult
instance_like_impl::verifyReferencedModule(Operation *instanceOp,
SymbolTableCollection &symbolTable,
mlir::FlatSymbolRefAttr moduleName) {
auto module = instanceOp->getParentOfType<FModuleOp>();
auto referencedModule =
symbolTable.lookupNearestSymbolFrom<FModuleLike>(instanceOp, moduleName);
if (!referencedModule) {
return instanceOp->emitOpError("invalid symbol reference");
}
// Check this is not a class.
if (isa<ClassOp /* ClassLike */>(referencedModule))
return instanceOp->emitOpError("must instantiate a module not a class")
.attachNote(referencedModule.getLoc())
<< "class declared here";
// Check that this instance doesn't recursively instantiate its wrapping
// module.
if (referencedModule == module) {
auto diag = instanceOp->emitOpError()
<< "is a recursive instantiation of its containing module";
return diag.attachNote(module.getLoc())
<< "containing module declared here";
}
// Small helper add a note to the original declaration.
auto emitNote = [&](InFlightDiagnostic &&diag) -> InFlightDiagnostic && {
diag.attachNote(referencedModule->getLoc())
<< "original module declared here";
return std::move(diag);
};
// Check that all the attribute arrays are the right length up front. This
// lets us safely use the port name in error messages below.
size_t numResults = instanceOp->getNumResults();
size_t numExpected = referencedModule.getNumPorts();
if (numResults != numExpected) {
return emitNote(instanceOp->emitOpError()
<< "has a wrong number of results; expected " << numExpected
<< " but got " << numResults);
}
auto portDirections =
instanceOp->getAttrOfType<IntegerAttr>("portDirections");
if (portDirections.getValue().getBitWidth() != numExpected)
return emitNote(
instanceOp->emitOpError("the number of port directions should be "
"equal to the number of results"));
auto portNames = instanceOp->getAttrOfType<ArrayAttr>("portNames");
if (portNames.size() != numExpected)
return emitNote(
instanceOp->emitOpError("the number of port names should be "
"equal to the number of results"));
auto portAnnotations =
instanceOp->getAttrOfType<ArrayAttr>("portAnnotations");
if (portAnnotations.size() != numExpected)
return emitNote(
instanceOp->emitOpError("the number of result annotations should be "
"equal to the number of results"));
// Check that the port names match the referenced module.
if (portNames != referencedModule.getPortNamesAttr()) {
// We know there is an error, try to figure out whats wrong.
auto moduleNames = referencedModule.getPortNamesAttr();
// First compare the sizes:
if (portNames.size() != moduleNames.size()) {
return emitNote(instanceOp->emitOpError()
<< "has a wrong number of directions; expected "
<< moduleNames.size() << " but got " << portNames.size());
}
// Next check the values:
for (size_t i = 0; i != numResults; ++i) {
if (portNames[i] != moduleNames[i]) {
return emitNote(instanceOp->emitOpError()
<< "name for port " << i << " must be "
<< moduleNames[i] << ", but got " << portNames[i]);
}
}
llvm_unreachable("should have found something wrong");
}
// Check that the types match.
for (size_t i = 0; i != numResults; i++) {
auto resultType = instanceOp->getResult(i).getType();
auto expectedType = referencedModule.getPortType(i);
if (resultType != expectedType) {
return emitNote(instanceOp->emitOpError()
<< "result type for " << portNames[i] << " must be "
<< expectedType << ", but got " << resultType);
}
}
// Check that the port directions are consistent with the referenced module's.
if (portDirections != referencedModule.getPortDirectionsAttr()) {
// We know there is an error, try to figure out whats wrong.
auto moduleDirectionAttr = referencedModule.getPortDirectionsAttr();
// First compare the sizes:
auto expectedWidth = moduleDirectionAttr.getValue().getBitWidth();
auto actualWidth = portDirections.getValue().getBitWidth();
if (expectedWidth != actualWidth) {
return emitNote(instanceOp->emitOpError()
<< "has a wrong number of directions; expected "
<< expectedWidth << " but got " << actualWidth);
}
// Next check the values.
auto instanceDirs = direction::unpackAttribute(portDirections);
auto moduleDirs = direction::unpackAttribute(moduleDirectionAttr);
for (size_t i = 0; i != numResults; ++i) {
if (instanceDirs[i] != moduleDirs[i]) {
return emitNote(instanceOp->emitOpError()
<< "direction for " << portNames[i] << " must be \""
<< direction::toString(moduleDirs[i])
<< "\", but got \""
<< direction::toString(instanceDirs[i]) << "\"");
}
}
llvm_unreachable("should have found something wrong");
}
return success();
}

View File

@ -14,6 +14,7 @@
#include "circt/Dialect/FIRRTL/CHIRRTLDialect.h"
#include "circt/Dialect/FIRRTL/FIRRTLAnnotations.h"
#include "circt/Dialect/FIRRTL/FIRRTLAttributes.h"
#include "circt/Dialect/FIRRTL/FIRRTLInstanceImplementation.h"
#include "circt/Dialect/FIRRTL/FIRRTLTypes.h"
#include "circt/Dialect/FIRRTL/FIRRTLUtils.h"
#include "circt/Dialect/FIRRTL/FIRRTLVisitors.h"
@ -2101,116 +2102,8 @@ InstanceOp::cloneAndInsertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
}
LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
auto module = (*this)->getParentOfType<FModuleOp>();
auto referencedModule = symbolTable.lookupNearestSymbolFrom<FModuleLike>(
*this, getModuleNameAttr());
if (!referencedModule) {
return emitOpError("invalid symbol reference");
}
// Check this is not a class.
if (isa<ClassOp /* ClassLike */>(referencedModule))
return emitOpError("must instantiate a module not a class")
.attachNote(referencedModule.getLoc())
<< "class declared here";
// Check that this instance doesn't recursively instantiate its wrapping
// module.
if (referencedModule == module) {
auto diag = emitOpError()
<< "is a recursive instantiation of its containing module";
return diag.attachNote(module.getLoc())
<< "containing module declared here";
}
// Small helper add a note to the original declaration.
auto emitNote = [&](InFlightDiagnostic &&diag) -> InFlightDiagnostic && {
diag.attachNote(referencedModule->getLoc())
<< "original module declared here";
return std::move(diag);
};
// Check that all the attribute arrays are the right length up front. This
// lets us safely use the port name in error messages below.
size_t numResults = getNumResults();
size_t numExpected = referencedModule.getNumPorts();
if (numResults != numExpected) {
return emitNote(emitOpError() << "has a wrong number of results; expected "
<< numExpected << " but got " << numResults);
}
if (getPortDirections().getBitWidth() != numExpected)
return emitNote(emitOpError("the number of port directions should be "
"equal to the number of results"));
if (getPortNames().size() != numExpected)
return emitNote(emitOpError("the number of port names should be "
"equal to the number of results"));
if (getPortAnnotations().size() != numExpected)
return emitNote(emitOpError("the number of result annotations should be "
"equal to the number of results"));
// Check that the port names match the referenced module.
if (getPortNamesAttr() != referencedModule.getPortNamesAttr()) {
// We know there is an error, try to figure out whats wrong.
auto instanceNames = getPortNames();
auto moduleNames = referencedModule.getPortNamesAttr();
// First compare the sizes:
if (instanceNames.size() != moduleNames.size()) {
return emitNote(emitOpError()
<< "has a wrong number of directions; expected "
<< moduleNames.size() << " but got "
<< instanceNames.size());
}
// Next check the values:
for (size_t i = 0; i != numResults; ++i) {
if (instanceNames[i] != moduleNames[i]) {
return emitNote(emitOpError()
<< "name for port " << i << " must be "
<< moduleNames[i] << ", but got " << instanceNames[i]);
}
}
llvm_unreachable("should have found something wrong");
}
// Check that the types match.
for (size_t i = 0; i != numResults; i++) {
auto resultType = getResult(i).getType();
auto expectedType = referencedModule.getPortType(i);
if (resultType != expectedType) {
return emitNote(emitOpError()
<< "result type for " << getPortName(i) << " must be "
<< expectedType << ", but got " << resultType);
}
}
// Check that the port directions are consistent with the referenced module's.
if (getPortDirectionsAttr() != referencedModule.getPortDirectionsAttr()) {
// We know there is an error, try to figure out whats wrong.
auto instanceDirectionAttr = getPortDirectionsAttr();
auto moduleDirectionAttr = referencedModule.getPortDirectionsAttr();
// First compare the sizes:
auto expectedWidth = moduleDirectionAttr.getValue().getBitWidth();
auto actualWidth = instanceDirectionAttr.getValue().getBitWidth();
if (expectedWidth != actualWidth) {
return emitNote(emitOpError()
<< "has a wrong number of directions; expected "
<< expectedWidth << " but got " << actualWidth);
}
// Next check the values.
auto instanceDirs = direction::unpackAttribute(instanceDirectionAttr);
auto moduleDirs = direction::unpackAttribute(moduleDirectionAttr);
for (size_t i = 0; i != numResults; ++i) {
if (instanceDirs[i] != moduleDirs[i]) {
return emitNote(emitOpError()
<< "direction for " << getPortName(i) << " must be \""
<< direction::toString(moduleDirs[i])
<< "\", but got \""
<< direction::toString(instanceDirs[i]) << "\"");
}
}
llvm_unreachable("should have found something wrong");
}
return success();
return instance_like_impl::verifyReferencedModule(*this, symbolTable,
getModuleNameAttr());
}
StringRef InstanceOp::getInstanceName() { return getName(); }

View File

@ -4,12 +4,12 @@ set(CIRCT_HW_Sources
HWAttributes.cpp
HWDialect.cpp
HWInstanceGraph.cpp
HWInstanceImplementation.cpp
HWModuleOpInterface.cpp
HWOpInterfaces.cpp
HWOps.cpp
HWTypeInterfaces.cpp
HWTypes.cpp
InstanceImplementation.cpp
ModuleImplementation.cpp
InnerSymbolTable.cpp
PortConverter.cpp

View File

@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
#include "circt/Dialect/HW/InstanceImplementation.h"
#include "circt/Dialect/HW/HWInstanceImplementation.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/HW/HWSymCache.h"

View File

@ -14,9 +14,9 @@
#include "circt/Dialect/Comb/CombOps.h"
#include "circt/Dialect/HW/CustomDirectiveImpl.h"
#include "circt/Dialect/HW/HWAttributes.h"
#include "circt/Dialect/HW/HWInstanceImplementation.h"
#include "circt/Dialect/HW/HWSymCache.h"
#include "circt/Dialect/HW/HWVisitors.h"
#include "circt/Dialect/HW/InstanceImplementation.h"
#include "circt/Dialect/HW/ModuleImplementation.h"
#include "circt/Support/CustomDirectiveImpl.h"
#include "circt/Support/Namespace.h"