Skip to content

Commit 8c75ba9

Browse files
committed
[Arc] Add ExecuteOp
Add a new `arc.execute` op which is similar to `scf.execute_region`. It allows an SSACFG region to be embedded in a graph region like an `hw.module`. In a later PR, a conversion from `llhd.combinational` to this new `arc.execute` will be added. We can't directly use `scf.execute_region` for this since that op eagerly inlines into the parent region even if the parent is a graph region. This does not preserve semantics in the case of HW modules.
1 parent 2fa9964 commit 8c75ba9

File tree

6 files changed

+113
-3
lines changed

6 files changed

+113
-3
lines changed

include/circt/Dialect/Arc/ArcOps.td

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def DefineOp : ArcOp<"define", [
113113

114114
def OutputOp : ArcOp<"output", [
115115
Terminator,
116-
ParentOneOf<["DefineOp", "LutOp", "ClockDomainOp"]>,
116+
ParentOneOf<["DefineOp", "LutOp", "ClockDomainOp", "ExecuteOp"]>,
117117
Pure,
118118
ReturnLike
119119
]> {
@@ -599,6 +599,35 @@ def StateWriteOp : ArcOp<"state_write", [
599599
}];
600600
}
601601

602+
//===----------------------------------------------------------------------===//
603+
// Procedural Ops
604+
//===----------------------------------------------------------------------===//
605+
606+
def ExecuteOp : ArcOp<"execute", [
607+
IsolatedFromAbove,
608+
RecursiveMemoryEffects,
609+
]> {
610+
let summary = "Execute an SSACFG region";
611+
let description = [{
612+
The `arc.execute` op allows an SSACFG region to be embedded in a parent
613+
graph region, or another SSACFG region. Whenever execution reaches this op,
614+
its body region is executed and the results yielded from the body are
615+
produced as the `arc.execute` op's results. The op is isolated from above.
616+
Any SSA values defined outside the op that are used inside the body have to
617+
be captured as operands and then referred to as entry block arguments in the
618+
body.
619+
}];
620+
let arguments = (ins Variadic<AnyType>:$inputs);
621+
let results = (outs Variadic<AnyType>:$results);
622+
let regions = (region MinSizedRegion<1>:$body);
623+
let assemblyFormat = [{
624+
(` ` `(` $inputs^ `:` type($inputs) `)`)?
625+
(`->` `(` type($results)^ `)`)?
626+
attr-dict-with-keyword $body
627+
}];
628+
let hasRegionVerifier = 1;
629+
}
630+
602631
//===----------------------------------------------------------------------===//
603632
// Simulation Orchestration
604633
//===----------------------------------------------------------------------===//

lib/Dialect/Arc/ArcOps.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,15 @@ LogicalResult SimStepOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
630630
return success();
631631
}
632632

633+
//===----------------------------------------------------------------------===//
634+
// ExecuteOp
635+
//===----------------------------------------------------------------------===//
636+
637+
LogicalResult ExecuteOp::verifyRegions() {
638+
return verifyTypeListEquivalence(*this, getInputs().getTypes(),
639+
getBody().getArgumentTypes(), "input");
640+
}
641+
633642
#include "circt/Dialect/Arc/ArcInterfaces.cpp.inc"
634643

635644
#define GET_OP_CLASSES

lib/Dialect/Arc/Transforms/LowerArcsToFuncs.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ struct OutputOpLowering : public OpConversionPattern<arc::OutputOp> {
5858
LogicalResult
5959
matchAndRewrite(arc::OutputOp op, OpAdaptor adaptor,
6060
ConversionPatternRewriter &rewriter) const final {
61+
if (!isa<arc::DefineOp, func::FuncOp>(op->getParentOp()))
62+
return failure();
6163
rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOutputs());
6264
return success();
6365
}
@@ -101,7 +103,9 @@ static void populateLegality(ConversionTarget &target) {
101103

102104
target.addIllegalOp<arc::CallOp>();
103105
target.addIllegalOp<arc::DefineOp>();
104-
target.addIllegalOp<arc::OutputOp>();
106+
target.addDynamicallyLegalOp<arc::OutputOp>([](auto op) {
107+
return !isa<arc::DefineOp, func::FuncOp>(op->getParentOp());
108+
});
105109
target.addIllegalOp<arc::StateOp>();
106110
}
107111

test/Dialect/Arc/basic-errors.mlir

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,3 +590,37 @@ hw.module @InvalidInitType(in %clock: !seq.clock, in %input: i7) {
590590
// expected-error @below {{failed to verify that types of initial arguments match result types}}
591591
%res = arc.state @Bar(%input) clock %clock initial (%cst: i8) latency 1 : (i7) -> i7
592592
}
593+
594+
// -----
595+
596+
// expected-error @below {{region with at least 1 blocks}}
597+
arc.execute {
598+
}
599+
600+
// -----
601+
602+
%0 = hw.constant 0 : i42
603+
// expected-error @below {{input type mismatch: input #0}}
604+
// expected-note @below {{expected type: 'i42'}}
605+
// expected-note @below {{actual type: 'i19'}}
606+
arc.execute (%0 : i42) {
607+
^bb0(%arg0: i19):
608+
arc.output
609+
}
610+
611+
// -----
612+
613+
arc.execute -> (i42) {
614+
// expected-error @below {{incorrect number of outputs: expected 1, but got 0}}
615+
arc.output
616+
}
617+
618+
// -----
619+
620+
arc.execute -> (i42) {
621+
%0 = hw.constant 0 : i19
622+
// expected-error @below {{output type mismatch: output #0}}
623+
// expected-note @below {{expected type: 'i42'}}
624+
// expected-note @below {{actual type: 'i19'}}
625+
arc.output %0 : i19
626+
}

test/Dialect/Arc/basic.mlir

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: circt-opt %s --verify-diagnostics | circt-opt | FileCheck %s
1+
// RUN: circt-opt --verify-diagnostics --verify-roundtrip %s | circt-opt | FileCheck %s
22

33
// CHECK-LABEL: arc.define @Foo
44
arc.define @Foo(%arg0: i42, %arg1: i9) -> (i42, i9) {
@@ -370,3 +370,26 @@ func.func @ReadsWrites(%arg0: !arc.state<i42>, %arg1: i42, %arg2: i1) {
370370
arc.state_write %arg0 = %arg1 if %arg2 : <i42>
371371
return
372372
}
373+
374+
func.func @Execute(%arg0: i42) {
375+
// CHECK: arc.execute {
376+
arc.execute {
377+
arc.output
378+
}
379+
// CHECK: arc.execute (%arg0 : i42) {
380+
arc.execute (%arg0 : i42) {
381+
^bb0(%0: i42):
382+
arc.output
383+
}
384+
// CHECK: arc.execute -> (i42) {
385+
arc.execute -> (i42) {
386+
%0 = hw.constant 1337 : i42
387+
arc.output %0 : i42
388+
}
389+
// CHECK: arc.execute (%arg0 : i42) -> (i42) {
390+
arc.execute (%arg0 : i42) -> (i42) {
391+
^bb0(%0: i42):
392+
arc.output %0 : i42
393+
}
394+
return
395+
}

test/Dialect/Arc/lower-arcs-to-funcs.mlir

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,14 @@ arc.define @sub1(%arg0: i32) -> i32 {
2828
arc.output %arg0 : i32
2929
// CHECK-NEXT: return %arg0 : i32
3030
}
31+
32+
// CHECK-LABEL: hw.module @DontConvertExecuteOps
33+
hw.module @DontConvertExecuteOps(in %arg0: i32, out out0: i32) {
34+
// CHECK: arc.execute
35+
// CHECK: arc.output
36+
%0 = arc.execute (%arg0 : i32) -> (i32) {
37+
^bb0(%1: i32):
38+
arc.output %1 : i32
39+
}
40+
hw.output %0 : i32
41+
}

0 commit comments

Comments
 (0)