diff --git a/include/circt/Dialect/FIRRTL/FIRRTLAnnotationHelper.h b/include/circt/Dialect/FIRRTL/FIRRTLAnnotationHelper.h index 69b5ffcde07e..838b0dddf4f9 100644 --- a/include/circt/Dialect/FIRRTL/FIRRTLAnnotationHelper.h +++ b/include/circt/Dialect/FIRRTL/FIRRTLAnnotationHelper.h @@ -253,10 +253,6 @@ std::optional resolvePath(StringRef rawPath, CircuitOp circuit, SymbolTable &symTbl, CircuitTargetCache &cache); -/// Return true if an Annotation's class name is handled by the LowerAnnotations -/// pass. -bool isAnnoClassLowered(StringRef className); - /// A representation of a deferred Wiring problem consisting of a source that /// should be connected to a sink. struct WiringProblem { @@ -437,6 +433,80 @@ InstanceOp addPortsToModule(FModuleLike mod, InstanceOp instOnPath, InstancePathCache &instancePathcache, CircuitTargetCache *targetCaches = nullptr); +///===----------------------------------------------------------------------===// +/// LowerAnnotations +///===----------------------------------------------------------------------===// + +/// Annotation resolver and handler. +struct AnnoRecord { + llvm::function_ref(DictionaryAttr, ApplyState &)> + resolver; + llvm::function_ref + applier; +}; + +/// Register external annotation records. +LogicalResult registerAnnotationRecord( + StringRef annoClass, AnnoRecord annoRecord, + const std::function &errorHandler = {}); + +///===----------------------------------------------------------------------===// +/// Standard Utility Resolvers +///===----------------------------------------------------------------------===// + +/// (SFC) FIRRTL SingleTargetAnnotation resolver. Uses the 'target' field of +/// the annotation with standard parsing to resolve the path. This requires +/// 'target' to exist and be normalized (per docs/FIRRTLAnnotations.md). +std::optional stdResolve(DictionaryAttr anno, ApplyState &state); + +/// Resolves with target, if it exists. If not, resolves to the circuit. +std::optional tryResolve(DictionaryAttr anno, ApplyState &state); + +///===----------------------------------------------------------------------===// +/// Standard Utility Appliers +///===----------------------------------------------------------------------===// + +/// An applier which puts the annotation on the target and drops the 'target' +/// field from the annotation. Optionally handles non-local annotations. +LogicalResult applyWithoutTargetImpl(const AnnoPathValue &target, + DictionaryAttr anno, ApplyState &state, + bool allowNonLocal); + +/// An applier which puts the annotation on the target and drops the 'target' +/// field from the annotation. Optionally handles non-local annotations. +/// Ensures the target resolves to an expected type of operation. +template +static LogicalResult applyWithoutTarget(const AnnoPathValue &target, + DictionaryAttr anno, + ApplyState &state) { + if (target.ref.isa()) { + if (!allowPortAnnoTarget) + return failure(); + } else if (!target.isOpOfType()) + return failure(); + + return applyWithoutTargetImpl(target, anno, state, allowNonLocal); +} + +template +static LogicalResult applyWithoutTarget(const AnnoPathValue &target, + DictionaryAttr anno, + ApplyState &state) { + return applyWithoutTarget(target, anno, + state); +} + +/// An applier which puts the annotation on the target and drops the 'target' +/// field from the annotaiton. Optionally handles non-local annotations. +template +static LogicalResult applyWithoutTarget(const AnnoPathValue &target, + DictionaryAttr anno, + ApplyState &state) { + return applyWithoutTargetImpl(target, anno, state, allowNonLocal); +} + } // namespace firrtl } // namespace circt diff --git a/lib/Dialect/FIRRTL/Transforms/LowerAnnotations.cpp b/lib/Dialect/FIRRTL/Transforms/LowerAnnotations.cpp index 927210ab70eb..72befb2e1d5b 100644 --- a/lib/Dialect/FIRRTL/Transforms/LowerAnnotations.cpp +++ b/lib/Dialect/FIRRTL/Transforms/LowerAnnotations.cpp @@ -163,8 +163,8 @@ static std::optional stdResolveImpl(StringRef rawPath, /// (SFC) FIRRTL SingleTargetAnnotation resolver. Uses the 'target' field of /// the annotation with standard parsing to resolve the path. This requires /// 'target' to exist and be normalized (per docs/FIRRTLAnnotations.md). -static std::optional stdResolve(DictionaryAttr anno, - ApplyState &state) { +std::optional circt::firrtl::stdResolve(DictionaryAttr anno, + ApplyState &state) { auto target = anno.getNamed("target"); if (!target) { mlir::emitError(state.circuit.getLoc()) @@ -180,8 +180,8 @@ static std::optional stdResolve(DictionaryAttr anno, } /// Resolves with target, if it exists. If not, resolves to the circuit. -static std::optional tryResolve(DictionaryAttr anno, - ApplyState &state) { +std::optional circt::firrtl::tryResolve(DictionaryAttr anno, + ApplyState &state) { auto target = anno.getNamed("target"); if (target) return stdResolveImpl(cast(target->getValue()).getValue(), @@ -195,10 +195,11 @@ static std::optional tryResolve(DictionaryAttr anno, /// An applier which puts the annotation on the target and drops the 'target' /// field from the annotation. Optionally handles non-local annotations. -static LogicalResult applyWithoutTargetImpl(const AnnoPathValue &target, - DictionaryAttr anno, - ApplyState &state, - bool allowNonLocal) { +LogicalResult circt::firrtl::applyWithoutTargetImpl(const AnnoPathValue &target, + + DictionaryAttr anno, + ApplyState &state, + bool allowNonLocal) { if (!allowNonLocal && !target.isLocal()) { Annotation annotation(anno); auto diag = mlir::emitError(target.ref.getOp()->getLoc()) @@ -223,47 +224,12 @@ static LogicalResult applyWithoutTargetImpl(const AnnoPathValue &target, return success(); } -/// An applier which puts the annotation on the target and drops the 'target' -/// field from the annotation. Optionally handles non-local annotations. -/// Ensures the target resolves to an expected type of operation. -template -static LogicalResult applyWithoutTarget(const AnnoPathValue &target, - DictionaryAttr anno, - ApplyState &state) { - if (target.ref.isa()) { - if (!allowPortAnnoTarget) - return failure(); - } else if (!target.isOpOfType()) - return failure(); - - return applyWithoutTargetImpl(target, anno, state, allowNonLocal); -} - -template -static LogicalResult applyWithoutTarget(const AnnoPathValue &target, - DictionaryAttr anno, - ApplyState &state) { - return applyWithoutTarget(target, anno, - state); -} - -/// An applier which puts the annotation on the target and drops the 'target' -/// field from the annotaiton. Optionally handles non-local annotations. -template -static LogicalResult applyWithoutTarget(const AnnoPathValue &target, - DictionaryAttr anno, - ApplyState &state) { - return applyWithoutTargetImpl(target, anno, state, allowNonLocal); -} - /// Just drop the annotation. This is intended for Annotations which are known, /// but can be safely ignored. -static LogicalResult drop(const AnnoPathValue &target, DictionaryAttr anno, - ApplyState &state) { +LogicalResult drop(const AnnoPathValue &target, DictionaryAttr anno, + ApplyState &state) { return success(); } - //===----------------------------------------------------------------------===// // Customized Appliers //===----------------------------------------------------------------------===// @@ -423,15 +389,7 @@ static LogicalResult applyLoadMemoryAnno(const AnnoPathValue &target, // Driving table //===----------------------------------------------------------------------===// -namespace { -struct AnnoRecord { - llvm::function_ref(DictionaryAttr, ApplyState &)> - resolver; - llvm::function_ref - applier; -}; - +namespace circt::firrtl { /// Resolution and application of a "firrtl.annotations.NoTargetAnnotation". /// This should be used for any Annotation which does not apply to anything in /// the FIRRTL Circuit, i.e., an Annotation which has no target. Historically, @@ -447,9 +405,7 @@ struct AnnoRecord { static AnnoRecord NoTargetAnnotation = {noResolve, applyWithoutTarget}; -} // end anonymous namespace - -static const llvm::StringMap annotationRecords{{ +static llvm::StringMap annotationRecords{{ // Testing Annotation {"circt.test", {stdResolve, applyWithoutTarget}}, @@ -555,6 +511,19 @@ static const llvm::StringMap annotationRecords{{ {wiringSourceAnnoClass, {stdResolve, applyWiring}}, {attributeAnnoClass, {stdResolve, applyAttributeAnnotation}}}}; +LogicalResult +registerAnnotationRecord(StringRef annoClass, AnnoRecord annoRecord, + const std::function &errorHandler) { + + if (annotationRecords.insert({annoClass, annoRecord}).second) + return LogicalResult::success(); + if (errorHandler) + errorHandler("annotation record '" + annoClass + "' is registered twice\n"); + return LogicalResult::failure(); +} + +} // namespace circt::firrtl + /// Lookup a record for a given annotation class. Optionally, returns the /// record for "circuit.missing" if the record doesn't exist. static const AnnoRecord *getAnnotationHandler(StringRef annoStr, @@ -567,10 +536,6 @@ static const AnnoRecord *getAnnotationHandler(StringRef annoStr, return nullptr; } -bool firrtl::isAnnoClassLowered(StringRef className) { - return annotationRecords.count(className); -} - //===----------------------------------------------------------------------===// // Pass Infrastructure //===----------------------------------------------------------------------===//