Skip to content

Commit b726cd2

Browse files
author
myuser
committed
Address review feedback: move LTL to Core lowering into LTLToCore pass
1 parent f3d910f commit b726cd2

File tree

10 files changed

+174
-216
lines changed

10 files changed

+174
-216
lines changed

include/circt/Tools/circt-bmc/Passes.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ namespace circt {
2323

2424
/// Generate the code for registering passes.
2525
#define GEN_PASS_DECL_LOWERTOBMC
26-
#define GEN_PASS_DECL_LOWERLTLTOBMC
2726
#define GEN_PASS_DECL_EXTERNALIZEREGISTERS
2827
#define GEN_PASS_REGISTRATION
2928
#include "circt/Tools/circt-bmc/Passes.h.inc"

include/circt/Tools/circt-bmc/Passes.td

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,6 @@ def LowerToBMC : Pass<"lower-to-bmc", "::mlir::ModuleOp"> {
4242
];
4343
}
4444

45-
def LowerLTLToBMC : Pass<"lower-ltl-to-bmc", "circt::hw::HWModuleOp"> {
46-
let summary = "Lower a subset of LTL to core logic for circt-bmc";
47-
let dependentDialects = [
48-
"circt::ltl::LTLDialect", "circt::seq::SeqDialect",
49-
"circt::comb::CombDialect", "circt::hw::HWDialect"
50-
];
51-
}
5245

5346
def ExternalizeRegisters : Pass<"externalize-registers", "::mlir::ModuleOp"> {
5447
let summary = "Removes registers and adds corresponding input and output ports";

lib/Conversion/LTLToCore/LTLToCore.cpp

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,159 @@ struct LowerLTLToCorePass
177177
: public circt::impl::LowerLTLToCoreBase<LowerLTLToCorePass> {
178178
LowerLTLToCorePass() = default;
179179
void runOnOperation() override;
180+
181+
private:
182+
int nameID = 0;
183+
184+
StringAttr nextName(OpBuilder &builder, StringRef prefix) {
185+
return builder.getStringAttr((prefix + "_" + Twine(nameID++)).str());
186+
}
187+
188+
Value createCompReg(OpBuilder &builder, Location loc, Value input, Value clk,
189+
StringRef prefix) {
190+
auto nameAttr = nextName(builder, prefix);
191+
auto i1 = builder.getI1Type();
192+
Value initZero = seq::createConstantInitialValue(
193+
builder, loc, builder.getIntegerAttr(i1, 0));
194+
return seq::CompRegOp::create(builder, loc, input, clk,
195+
/*reset*/ Value(), /*rstValue*/ Value(),
196+
nameAttr, /*initialValue*/ initZero)
197+
.getResult();
198+
}
199+
200+
Value shift(OpBuilder &builder, Location loc, Value input, Value clk,
201+
int64_t cycles, StringRef prefix) {
202+
Value cur = input;
203+
for (int64_t i = 0; i < cycles; ++i) {
204+
cur = createCompReg(builder, loc, cur, clk, prefix);
205+
}
206+
return cur;
207+
}
208+
209+
FailureOr<Value> getSeqClock(Value clkI1) {
210+
if (isa<seq::ClockType>(clkI1.getType()))
211+
return clkI1;
212+
if (auto from = clkI1.getDefiningOp<seq::FromClockOp>())
213+
return from.getInput();
214+
return failure();
215+
}
216+
217+
FailureOr<Value> lowerImplicationWithDelay(OpBuilder &builder, Location loc,
218+
Value antecedent, ltl::DelayOp delay,
219+
Value clkI1) {
220+
if (!antecedent.getType().isInteger(1))
221+
return failure();
222+
if (!delay.getInput().getType().isInteger(1))
223+
return failure();
224+
225+
int64_t start = static_cast<int64_t>(delay.getDelay());
226+
if (start < 1)
227+
return failure();
228+
229+
auto lengthAttr = delay.getLength();
230+
if (!lengthAttr)
231+
return failure();
232+
int64_t length = static_cast<int64_t>(*lengthAttr);
233+
if (length < 0)
234+
return failure();
235+
int64_t end = start + length;
236+
237+
auto clkOr = getSeqClock(clkI1);
238+
if (failed(clkOr))
239+
return failure();
240+
Value clk = *clkOr;
241+
242+
// Exact delay case: antecedent delayed by start cycles implies consequent now.
243+
if (length == 0) {
244+
Value delayed = shift(builder, loc, antecedent, clk, start, "ltl_delay");
245+
Value notDelayed = comb::createOrFoldNot(loc, delayed, builder);
246+
auto orOp = comb::OrOp::create(builder, loc, ValueRange{notDelayed, delay.getInput()}, false);
247+
return orOp.getResult();
248+
}
249+
250+
// Bounded range case: if antecedent fires, consequent must hold at least
251+
// once in [start, end] cycles. Use a pending-request monitor that clears
252+
// when consequent is observed.
253+
Value notRight = comb::createOrFoldNot(loc, delay.getInput(), builder);
254+
255+
// Age 1 pending is the antecedent delayed by 1 cycle.
256+
Value pending = shift(builder, loc, antecedent, clk, 1, "ltl_delay");
257+
Value prev = pending;
258+
259+
for (int64_t age = 1; age <= end; ++age) {
260+
Value nextVal;
261+
if (age == 1) {
262+
nextVal = prev;
263+
} else if (age < start) {
264+
nextVal = prev;
265+
} else {
266+
auto andOp = comb::AndOp::create(builder, loc, ValueRange{prev, notRight}, false);
267+
nextVal = andOp.getResult();
268+
}
269+
prev = createCompReg(builder, loc, nextVal, clk, "ltl_window");
270+
}
271+
272+
// violation = pending_at_end AND NOT(consequent)
273+
auto viol = comb::AndOp::create(builder, loc, ValueRange{prev, notRight}, false);
274+
Value notViol = comb::createOrFoldNot(loc, viol.getResult(), builder);
275+
return notViol;
276+
}
277+
278+
FailureOr<Value> lowerClockedProperty(OpBuilder &builder, Location loc,
279+
Value prop, Value clkI1) {
280+
if (auto imp = prop.getDefiningOp<ltl::ImplicationOp>()) {
281+
auto delay = imp.getConsequent().getDefiningOp<ltl::DelayOp>();
282+
if (!delay)
283+
return failure();
284+
return lowerImplicationWithDelay(builder, loc, imp.getAntecedent(), delay,
285+
clkI1);
286+
}
287+
if (prop.getType().isInteger(1))
288+
return prop;
289+
return failure();
290+
}
180291
};
181292
} // namespace
182293

183294
// Simply applies the conversion patterns defined above
184295
void LowerLTLToCorePass::runOnOperation() {
296+
hw::HWModuleOp hwModule = getOperation();
297+
OpBuilder builder(hwModule);
298+
bool failedLowering = false;
299+
300+
auto lowerAssertLike = [&](Operation *op, Value prop) {
301+
auto clkOp = prop.getDefiningOp<ltl::ClockOp>();
302+
if (!clkOp)
303+
return;
304+
OpBuilder::InsertionGuard guard(builder);
305+
builder.setInsertionPoint(op);
306+
307+
auto lowered = lowerClockedProperty(builder, op->getLoc(), clkOp.getInput(),
308+
clkOp.getClock());
309+
if (failed(lowered)) {
310+
op->emitError("unsupported LTL delay pattern for LowerLTLToCore");
311+
failedLowering = true;
312+
return;
313+
}
314+
op->setOperand(0, *lowered);
315+
if (clkOp->use_empty())
316+
clkOp.erase();
317+
};
318+
319+
hwModule.walk([&](verif::AssertOp op) {
320+
if (failedLowering)
321+
return;
322+
lowerAssertLike(op, op.getProperty());
323+
});
324+
325+
hwModule.walk([&](verif::AssumeOp op) {
326+
if (failedLowering)
327+
return;
328+
lowerAssertLike(op, op.getProperty());
329+
});
330+
331+
if (failedLowering)
332+
return signalPassFailure();
185333

186334
// Set target dialects: We don't want to see any ltl or verif that might
187335
// come from an AssertProperty left in the result

lib/Tools/circt-bmc/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
add_circt_library(CIRCTBMCTransforms
22
ExternalizeRegisters.cpp
3-
LowerLTLToBMC.cpp
43
LowerToBMC.cpp
54

65
DEPENDS

lib/Tools/circt-bmc/LowerLTLToBMC.cpp

Lines changed: 0 additions & 190 deletions
This file was deleted.
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
// RUN: not circt-bmc %s --module=ltl_bad -b 2 --emit-mlir 2>&1 | FileCheck %s
2-
// CHECK: error: unsupported LTL pattern for circt-bmc lowering
1+
// RUN: circt-opt %s --lower-ltl-to-core --verify-diagnostics
32

43
hw.module @ltl_bad(in %clk: !seq.clock, in %req: i1, in %ack: i1) attributes {num_regs = 0 : i32, initial_values = []} {
5-
// Unbounded delay is not supported by lower-ltl-to-bmc.
4+
// Unbounded delay is not supported by lower-ltl-to-core.
65
%seq = ltl.delay %ack, 2 : i1
76
%imp = ltl.implication %req, %seq : i1, !ltl.sequence
87
%clk_i1 = seq.from_clock %clk
98
%prop = ltl.clock %imp, posedge %clk_i1 : !ltl.property
9+
// expected-error @below {{unsupported LTL delay pattern for LowerLTLToCore}}
1010
verif.assert %prop : !ltl.property
1111
hw.output
12-
}
12+
}

0 commit comments

Comments
 (0)