From d47ffe2d90e9aa970d9401e1846559c941a09a84 Mon Sep 17 00:00:00 2001 From: Schuyler Eldridge Date: Fri, 26 Jan 2024 20:04:17 -0500 Subject: [PATCH] fixup! [FIRRTL] Prerequisites for Layer-Associated Probes --- .../circt/Dialect/FIRRTL/FIRRTLExpressions.td | 1 + lib/Dialect/FIRRTL/FIRRTLOps.cpp | 40 +++++++++++++++++++ test/Dialect/FIRRTL/errors.mlir | 29 ++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/include/circt/Dialect/FIRRTL/FIRRTLExpressions.td b/include/circt/Dialect/FIRRTL/FIRRTLExpressions.td index ebf873de4523..7918c5cfca72 100644 --- a/include/circt/Dialect/FIRRTL/FIRRTLExpressions.td +++ b/include/circt/Dialect/FIRRTL/FIRRTLExpressions.td @@ -1239,6 +1239,7 @@ def RefResolveOp: FIRRTLExprOp<"ref.resolve", let results = (outs FIRRTLBaseType:$result); let hasCanonicalizer = true; + let hasVerifier = 1; let assemblyFormat = "$ref attr-dict `:` qualified(type($ref))"; } diff --git a/lib/Dialect/FIRRTL/FIRRTLOps.cpp b/lib/Dialect/FIRRTL/FIRRTLOps.cpp index b48809c9b179..73e4014bff19 100644 --- a/lib/Dialect/FIRRTL/FIRRTLOps.cpp +++ b/lib/Dialect/FIRRTL/FIRRTLOps.cpp @@ -5810,6 +5810,46 @@ LogicalResult RefCastOp::verify() { return success(); } +LogicalResult RefResolveOp::verify() { + + SymbolRefAttr layer; + auto layerBlockOp = (*this)->getParentOfType(); + if (layerBlockOp) + layer = layerBlockOp.getLayerName(); + + // The dest layer must be the same as the source layer or a parent of it. + SymbolRefAttr layerPointer = layer; + auto destLayer = getRef().getType().getLayer(); + for (;;) { + if (layerPointer == destLayer) + break; + + if (!layerPointer) { + if (!layer) + return emitOpError() << "cannot read from a layer-colored probe from " + "outside a layerblock"; + auto diag = emitOpError() + << "reads from a probe colored with layer '" << destLayer + << "' from a layerblock associated with layer '" << layer + << "'. The resolve op must be in a layerblock associated " + "with or a child of layer '" + << destLayer << "'."; + return diag.attachNote(layerBlockOp.getLoc()) + << "the layerblock was declared here"; + } + + if (layerPointer.getNestedReferences().empty()) { + layerPointer = {}; + continue; + } + layerPointer = + SymbolRefAttr::get(layerPointer.getRootReference(), + layerPointer.getNestedReferences().drop_back()); + } + + return success(); +} + LogicalResult RWProbeOp::verifyInnerRefs(hw::InnerRefNamespace &ns) { auto targetRef = getTarget(); if (targetRef.getModule() != diff --git a/test/Dialect/FIRRTL/errors.mlir b/test/Dialect/FIRRTL/errors.mlir index f9e7b9ec7e22..b694a408e4d1 100644 --- a/test/Dialect/FIRRTL/errors.mlir +++ b/test/Dialect/FIRRTL/errors.mlir @@ -1947,6 +1947,35 @@ firrtl.circuit "IllegalRefCastDestLayerBlock" { // ----- +firrtl.circuit "IllegalRefResolve_NotInLayerBlock" { + firrtl.layer @A bind { + } + firrtl.module @IllegalRefResolve_NotInLayerBlock() { + %0 = firrtl.wire : !firrtl.probe, @A> + // expected-error @below {{'firrtl.ref.resolve' op cannot read from a layer-colored probe from outside a layerblock}} + %1 = firrtl.ref.resolve %0 : !firrtl.probe, @A> + } +} + +// ----- + +firrtl.circuit "IllegalRefResolve_IllegalLayer" { + firrtl.layer @A bind { + } + firrtl.layer @B bind { + } + firrtl.module @IllegalRefResolve_IllegalLayer() { + %0 = firrtl.wire : !firrtl.probe, @A> + // expected-note @below {{the layerblock was declared here}} + firrtl.layerblock @B { + // expected-error @below {{'firrtl.ref.resolve' op reads from a probe colored with layer '@A' from a layerblock associated with layer '@B'. The resolve op must be in a layerblock associated with or a child of layer '@A'.}} + %1 = firrtl.ref.resolve %0 : !firrtl.probe, @A> + } + } +} + +// ----- + firrtl.circuit "InvalidProbeAssociationPort_SymbolDoesNotExist" { // expected-error @below {{probe port 'a' is associated with layer '@B', but this layer was not defined}} firrtl.module @InvalidProbeAssociationPort_SymbolDoesNotExist(out %a: !firrtl.probe, @B>) {