Skip to content

Commit 60aac81

Browse files
xls-github-botcopybara-github
authored andcommitted
[mlir] Add xls.cover operation to XLS MLIR.
This change introduces the `xls.cover` operation, which corresponds to the XLS IR `cover` node. Translation is implemented in both directions between XLS IR and MLIR. Test cases are added for both MLIR-to-XLS and XLS-to-MLIR translation of the `cover` operation. The MLIR-to-XLS translation logic is updated to correctly handle operations that do not produce a result. PiperOrigin-RevId: 939971774
1 parent be5dd5d commit 60aac81

5 files changed

Lines changed: 77 additions & 6 deletions

File tree

xls/contrib/mlir/IR/xls_ops.td

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,6 +2352,30 @@ def Xls_AssertOp : Xls_Op<"assert"> {
23522352
}];
23532353
}
23542354

2355+
def Xls_CoverOp : Xls_Op<"cover"> {
2356+
let summary = "Records every time the condition evaluates to true";
2357+
let description = [{
2358+
Records the number of times the given 'condition' evaluates to true. When
2359+
lowered to SystemVerilog, the 'label' becomes an identifier that should be
2360+
unique within the scope of emission, though uniqueness is not enforced by
2361+
either MLIR or XLS.
2362+
2363+
The op has no return value, which is noteworthy for two reasons: (1) Unlike
2364+
`xls.assert`, `xls.cover` does not take a token input and does not produce a
2365+
token output. (2) In XLS IR, the op returns an empty tuple but does so only
2366+
because there is no other way to express "no return value" type. This design
2367+
is more idiomatic in MLIR, at the cost of a small structural difference from
2368+
XLS IR.
2369+
}];
2370+
let arguments = (ins
2371+
I1:$condition,
2372+
StrAttr:$label
2373+
);
2374+
let assemblyFormat = [{
2375+
$condition `,` $label attr-dict
2376+
}];
2377+
}
2378+
23552379
def Xls_GateOp :
23562380
Xls_Op<"gate", [
23572381
ShapesAreConsistent<["data", "result"]>,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: xls_translate --mlir-xls-to-xls %s -- 2>&1 \
2+
// RUN: | FileCheck %s --dump-input-filter=all
3+
4+
// CHECK-LABEL: top fn test_cover(
5+
// CHECK-SAME: [[ARG0:.*]]: bits[1]
6+
// CHECK: cover([[ARG0]], label="my_coverpoint"
7+
func.func @test_cover(%arg0: i1) {
8+
xls.cover %arg0, "my_coverpoint"
9+
func.return
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: xls_translate --xls-to-mlir-xls %s 2>&1 | FileCheck %s
2+
3+
package translate_ops
4+
5+
// CHECK-LABEL: func @test_cover(
6+
// CHECK-SAME: %[[COND:.*]]: i1)
7+
fn test_cover(cond: bits[1] id=1) -> bits[1] {
8+
// CHECK: xls.cover %[[COND]], "my_coverpoint"
9+
cover.2: () = cover(cond, label="my_coverpoint", id=2)
10+
ret not.3: bits[1] = not(cond, id=3)
11+
}

xls/contrib/mlir/tools/xls_translate/xls_translate_from_mlir.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,11 @@ BValue convertOp(AssertOp op, const TranslationState& state, BuilderBase& fb) {
513513
state.getLoc(op));
514514
}
515515

516+
BValue convertOp(CoverOp op, const TranslationState& state, BuilderBase& fb) {
517+
return fb.Cover(state.getXlsValue(op.getCondition()), op.getLabel(),
518+
state.getLoc(op));
519+
}
520+
516521
// Tuple operations
517522
BValue convertOp(TupleOp op, const TranslationState& state, BuilderBase& fb) {
518523
std::vector<BValue> values;
@@ -1208,7 +1213,7 @@ FailureOr<BValue> convertFunction(TranslationState& translation_state,
12081213
// Debugging ops
12091214
TraceOp,
12101215
// Misc. side-effecting ops
1211-
AssertOp, GateOp>(
1216+
AssertOp, CoverOp, GateOp>(
12121217
[&](auto t) { return convertOp(t, translation_state, fb); })
12131218
.Case<func::ReturnOp, YieldOp>([&](auto ret) {
12141219
if (ret.getNumOperands() == 1) {

xls/contrib/mlir/tools/xls_translate/xls_translate_to_mlir.cc

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,22 @@ absl::StatusOr<Operation*> translateOp(::xls::Assert& node, OpBuilder& builder,
13201320
: nullptr);
13211321
}
13221322

1323+
absl::StatusOr<Operation*> translateOp(::xls::Cover& node, OpBuilder& builder,
1324+
TranslationState& state) {
1325+
auto condition = state.getMlirValue(node.condition()->id());
1326+
if (!condition.ok()) {
1327+
return condition.status();
1328+
}
1329+
1330+
auto loc = translateLoc(node.loc(), builder, state);
1331+
if (!loc.ok()) {
1332+
return loc.status();
1333+
}
1334+
1335+
return CoverOp::create(builder, *loc, *condition,
1336+
builder.getStringAttr(node.label()));
1337+
}
1338+
13231339
absl::StatusOr<Operation*> translateAnyOp(::xls::Node& xls_node,
13241340
OpBuilder& builder,
13251341
TranslationState& state) {
@@ -1402,8 +1418,9 @@ absl::StatusOr<Operation*> translateAnyOp(::xls::Node& xls_node,
14021418
"StateRead not handeled during proc translation.");
14031419
} else if (dynamic_cast<::xls::Next*>(&xls_node)) {
14041420
return absl::InternalError("Next not handeled during proc translation.");
1405-
} else if (dynamic_cast<::xls::Cover*>(&xls_node) ||
1406-
dynamic_cast<::xls::MinDelay*>(&xls_node)) {
1421+
} else if (auto* xls_op = dynamic_cast<::xls::Cover*>(&xls_node)) {
1422+
op = translateOp(*xls_op, builder, state);
1423+
} else if (dynamic_cast<::xls::MinDelay*>(&xls_node)) {
14071424
return absl::InternalError(absl::StrCat(
14081425
"Unsupported operation: ", ::xls::OpToString(xls_node.op()),
14091426
" - Not yet available in XLS MLIR!"));
@@ -1416,9 +1433,13 @@ absl::StatusOr<Operation*> translateAnyOp(::xls::Node& xls_node,
14161433
return op.status();
14171434
}
14181435

1419-
if (auto err = state.setMlirValue(xls_node.id(), (*op)->getResult(0));
1420-
!err.ok()) {
1421-
return err;
1436+
// Only map the result if the op produces one (e.g., xls.cover has no
1437+
// results).
1438+
if ((*op)->getNumResults() > 0) {
1439+
if (auto err = state.setMlirValue(xls_node.id(), (*op)->getResult(0));
1440+
!err.ok()) {
1441+
return err;
1442+
}
14221443
}
14231444

14241445
return *op;

0 commit comments

Comments
 (0)