mirror of https://github.com/llvm/circt.git
hw.probe for late binding to nameless values (#2443)
This provides a way to refer to values without pre-binding a name. Thus the implementation of the device holding a value is unspecified, simply constrained such that at emission time, a namable entity will exist with the value in it. This will be used for bind and XMRs and in verbatim name-substitutions.
This commit is contained in:
parent
8cc1a1a514
commit
67a8d24ce8
|
@ -211,6 +211,6 @@ def ProbeOp : FIRRTLOp<"probe"> {
|
|||
let arguments = (ins SymbolNameAttr:$inner_sym, Variadic<FIRRTLType>:$operands);
|
||||
let results = (outs);
|
||||
|
||||
let assemblyFormat = "$inner_sym `(` $operands `)` attr-dict `:` type($operands)";
|
||||
let assemblyFormat = "$inner_sym attr-dict ( `,` $operands^ `:` type($operands))?";
|
||||
}
|
||||
|
||||
|
|
|
@ -154,10 +154,10 @@ public:
|
|||
auto *thisCast = static_cast<ConcreteType *>(this);
|
||||
return TypeSwitch<Operation *, ResultType>(op)
|
||||
.template Case<AttachOp, ConnectOp, PartialConnectOp, ForceOp, PrintFOp,
|
||||
SkipOp, StopOp, WhenOp, AssertOp, AssumeOp, CoverOp>(
|
||||
[&](auto opNode) -> ResultType {
|
||||
return thisCast->visitStmt(opNode, args...);
|
||||
})
|
||||
SkipOp, StopOp, WhenOp, AssertOp, AssumeOp, CoverOp,
|
||||
ProbeOp>([&](auto opNode) -> ResultType {
|
||||
return thisCast->visitStmt(opNode, args...);
|
||||
})
|
||||
.Default([&](auto expr) -> ResultType {
|
||||
return thisCast->visitInvalidStmt(op, args...);
|
||||
});
|
||||
|
@ -191,6 +191,8 @@ public:
|
|||
HANDLE(AssertOp);
|
||||
HANDLE(AssumeOp);
|
||||
HANDLE(CoverOp);
|
||||
HANDLE(ProbeOp);
|
||||
|
||||
#undef HANDLE
|
||||
};
|
||||
|
||||
|
|
|
@ -458,3 +458,20 @@ def GlobalRefOp : HWOp<"globalRef", [IsolatedFromAbove, Symbol]> {
|
|||
|
||||
let verifier = "return this->verifyGlobalRef();";
|
||||
}
|
||||
|
||||
def ProbeOp : HWOp<"probe", []> {
|
||||
let summary = "Probe values for use in remote references";
|
||||
let description = [{
|
||||
Captures values without binding to any accidental name. This allows
|
||||
capturing names holding values of interest while allowing the name to
|
||||
resolved only at emission time.
|
||||
}];
|
||||
|
||||
let arguments = (ins SymbolNameAttr:$inner_sym,
|
||||
Variadic<AnyType>:$operands);
|
||||
let results = (outs);
|
||||
|
||||
let assemblyFormat = "$inner_sym attr-dict (`,` $operands^ `:` type($operands))?";
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ public:
|
|||
ResultType dispatchStmtVisitor(Operation *op, ExtraArgs... args) {
|
||||
auto *thisCast = static_cast<ConcreteType *>(this);
|
||||
return TypeSwitch<Operation *, ResultType>(op)
|
||||
.template Case<OutputOp, InstanceOp, TypeScopeOp, TypedeclOp>(
|
||||
.template Case<ProbeOp, OutputOp, InstanceOp, TypeScopeOp, TypedeclOp>(
|
||||
[&](auto expr) -> ResultType {
|
||||
return thisCast->visitStmt(expr, args...);
|
||||
})
|
||||
|
@ -118,6 +118,7 @@ public:
|
|||
}
|
||||
|
||||
// Basic nodes.
|
||||
HANDLE(ProbeOp, Unhandled);
|
||||
HANDLE(OutputOp, Unhandled);
|
||||
HANDLE(InstanceOp, Unhandled);
|
||||
HANDLE(TypeScopeOp, Unhandled);
|
||||
|
|
|
@ -2399,6 +2399,7 @@ private:
|
|||
LogicalResult visitSV(ReleaseOp op);
|
||||
LogicalResult visitSV(AliasOp op);
|
||||
LogicalResult visitSV(InterfaceInstanceOp op);
|
||||
LogicalResult visitStmt(ProbeOp op);
|
||||
LogicalResult visitStmt(OutputOp op);
|
||||
LogicalResult visitStmt(InstanceOp op);
|
||||
LogicalResult visitStmt(TypeScopeOp op);
|
||||
|
@ -3405,6 +3406,10 @@ LogicalResult StmtEmitter::visitStmt(InstanceOp op) {
|
|||
return success();
|
||||
}
|
||||
|
||||
// Probes only exist to provide naming to values. They are handled in
|
||||
// the naming prepass.
|
||||
LogicalResult StmtEmitter::visitStmt(ProbeOp op) { return success(); }
|
||||
|
||||
// This may be called in the top-level, not just in an hw.module. Thus we can't
|
||||
// use the name map to find expression names for arguments to the instance, nor
|
||||
// do we need to emit subexpressions. Prepare pass, which has run for all
|
||||
|
|
|
@ -1419,6 +1419,7 @@ struct FIRRTLLowering : public FIRRTLVisitor<FIRRTLLowering, LogicalResult> {
|
|||
LogicalResult visitStmt(AssumeOp op);
|
||||
LogicalResult visitStmt(CoverOp op);
|
||||
LogicalResult visitStmt(AttachOp op);
|
||||
LogicalResult visitStmt(ProbeOp op);
|
||||
|
||||
private:
|
||||
/// The module we're lowering into.
|
||||
|
@ -3695,3 +3696,21 @@ LogicalResult FIRRTLLowering::visitStmt(AttachOp op) {
|
|||
|
||||
return success();
|
||||
}
|
||||
|
||||
LogicalResult FIRRTLLowering::visitStmt(ProbeOp op) {
|
||||
SmallVector<Value, 4> operands;
|
||||
operands.reserve(op.operands().size());
|
||||
for (auto operand : op.operands()) {
|
||||
operands.push_back(getLoweredValue(operand));
|
||||
if (!operands.back()) {
|
||||
// If this is a zero bit operand, just pass a one bit zero.
|
||||
if (!isZeroBitFIRRTLType(operand.getType()))
|
||||
return failure();
|
||||
operands.back() = getOrCreateIntConstant(1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
builder.create<hw::ProbeOp>(op.inner_sym(), operands);
|
||||
|
||||
return success();
|
||||
}
|
||||
|
|
|
@ -475,6 +475,7 @@ hw.module @bind_rename_port(%.io_req_ready.output: i1, %reset: i1, %clock: i1) {
|
|||
hw.module @SiFive_MulDiv(%clock: i1, %reset: i1) -> (io_req_ready: i1) {
|
||||
%false = hw.constant false
|
||||
hw.instance "InvisibleBind_assert" sym @__ETC_SiFive_MulDiv_assert @bind_rename_port(".io_req_ready.output": %false: i1, reset: %reset: i1, clock: %clock: i1) -> () {doNotPrint = true}
|
||||
hw.probe @__ETC_SiFive_MulDiv_assert, %false, %reset, %clock: i1,i1,i1
|
||||
hw.output %false : i1
|
||||
}
|
||||
|
||||
|
|
|
@ -581,6 +581,8 @@ firrtl.circuit "Simple" attributes {annotations = [{class =
|
|||
}
|
||||
|
||||
firrtl.module @bar(in %io_cpu_flush: !firrtl.uint<1>) {
|
||||
// CHECK: hw.probe @baz, %io_cpu_flush, %io_cpu_flush : i1, i1
|
||||
firrtl.probe @baz, %io_cpu_flush, %io_cpu_flush : !firrtl.uint<1>, !firrtl.uint<1>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: hw.module @foo
|
||||
|
|
|
@ -165,8 +165,8 @@ firrtl.module @ProbeTest(in %in1 : !firrtl.uint<2>, in %in2 : !firrtl.uint<3>, o
|
|||
firrtl.connect %w1, %w2 : !firrtl.uint<4>, !firrtl.uint<4>
|
||||
firrtl.connect %out3, %in2 : !firrtl.uint<3>, !firrtl.uint<3>
|
||||
%someNode = firrtl.node %in1 : !firrtl.uint<2>
|
||||
// CHECK: firrtl.probe @foobar(%in1, %in2, %out3, %w1, %[[TMP3]], %someNode) : !firrtl.uint<2>, !firrtl.uint<3>, !firrtl.uint<3>, !firrtl.uint<4>, !firrtl.uint<4>, !firrtl.uint<2>
|
||||
firrtl.probe @foobar (%in1, %in2, %out3, %w1, %w2, %someNode) : !firrtl.uint<2>, !firrtl.uint<3>, !firrtl.uint<3>, !firrtl.uint<4>, !firrtl.uint<4>, !firrtl.uint<2>
|
||||
// CHECK: firrtl.probe @foobar, %in1, %in2, %out3, %w1, %[[TMP3]], %someNode : !firrtl.uint<2>, !firrtl.uint<3>, !firrtl.uint<3>, !firrtl.uint<4>, !firrtl.uint<4>, !firrtl.uint<2>
|
||||
firrtl.probe @foobar, %in1, %in2, %out3, %w1, %w2, %someNode : !firrtl.uint<2>, !firrtl.uint<3>, !firrtl.uint<3>, !firrtl.uint<4>, !firrtl.uint<4>, !firrtl.uint<2>
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue