CIRCT  20.0.0git
RemoveGroups.cpp
Go to the documentation of this file.
1 //===- RemoveGroups.cpp - Remove Groups Pass --------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Contains the definitions of the Remove Groups pass.
10 //
11 //===----------------------------------------------------------------------===//
12 
16 #include "circt/Support/LLVM.h"
17 #include "mlir/IR/BuiltinTypes.h"
18 #include "mlir/IR/OperationSupport.h"
19 
20 namespace circt {
21 namespace calyx {
22 #define GEN_PASS_DEF_REMOVEGROUPS
23 #include "circt/Dialect/Calyx/CalyxPasses.h.inc"
24 } // namespace calyx
25 } // namespace circt
26 
27 using namespace circt;
28 using namespace calyx;
29 using namespace mlir;
30 
31 /// Makes several modifications to the operations of a GroupOp:
32 /// 1. Assign the 'done' signal of the component with the done_op of the top
33 /// level control group.
34 /// 2. Append the 'go' signal of the component to guard of each assignment.
35 /// 3. Replace all uses of GroupGoOp with the respective guard, and delete the
36 /// GroupGoOp.
37 /// 4. Remove the GroupDoneOp.
38 static void modifyGroupOperations(ComponentOp component) {
39  auto control = component.getControlOp();
40  // Get the only EnableOp in the control.
41  auto topLevel = *control.getRegion().getOps<EnableOp>().begin();
42  auto topLevelName = topLevel.getGroupName();
43 
44  auto wires = component.getWiresOp();
45  Value componentGoPort = component.getGoPort();
46  wires.walk([&](GroupOp group) {
47  auto &groupRegion = group->getRegion(0);
48  OpBuilder builder(groupRegion);
49  // Walk the assignments and append component's 'go' signal to each guard.
50  updateGroupAssignmentGuards(builder, group, componentGoPort);
51 
52  auto groupDone = group.getDoneOp();
53  if (topLevelName == group.getSymName()) {
54  // Replace `calyx.group_done %0, %1 ? : i1`
55  // with `calyx.assign %done, %0, %1 ? : i1`
56  auto assignOp =
57  builder.create<AssignOp>(group->getLoc(), component.getDonePort(),
58  groupDone.getSrc(), groupDone.getGuard());
59  groupDone->replaceAllUsesWith(assignOp);
60  } else {
61  // Replace calyx.group_go's uses with its guard, e.g.
62  // %A.go = calyx.group_go %true, %3 ? : i1
63  // %0 = comb.and %1, %A.go : i1
64  // ->
65  // %0 = comb.and %1, %3 : i1
66  auto groupGo = group.getGoOp();
67  auto groupGoGuard = groupGo.getGuard();
68  groupGo.replaceAllUsesWith(groupGoGuard);
69  groupGo->erase();
70  }
71  // In either case, remove the group's done value.
72  groupDone->erase();
73  });
74 }
75 
76 /// Inlines each group in the WiresOp.
77 void inlineGroups(ComponentOp component) {
78  auto &wiresRegion = component.getWiresOp().getRegion();
79  auto &wireBlocks = wiresRegion.getBlocks();
80  auto lastBlock = wiresRegion.end();
81 
82  // Inline the body of each group as a Block into the WiresOp.
83  wiresRegion.walk([&](GroupOp group) {
84  wireBlocks.splice(lastBlock, group.getRegion().getBlocks());
85  group->erase();
86  });
87 
88  // Merge the operations of each Block into the first block of the WiresOp.
89  auto firstBlock = wireBlocks.begin();
90  for (auto it = firstBlock, e = lastBlock; it != e; ++it) {
91  if (it == firstBlock)
92  continue;
93  firstBlock->getOperations().splice(firstBlock->end(), it->getOperations());
94  }
95 
96  // Erase the (now) empty blocks.
97  while (&wiresRegion.front() != &wiresRegion.back())
98  wiresRegion.back().erase();
99 }
100 
101 namespace {
102 
103 struct RemoveGroupsPass
104  : public circt::calyx::impl::RemoveGroupsBase<RemoveGroupsPass> {
105  void runOnOperation() override;
106 };
107 
108 } // end anonymous namespace
109 
110 void RemoveGroupsPass::runOnOperation() {
111  ComponentOp component = getOperation();
112 
113  // Early exit if there is no control to compile.
114  if (component.getControlOp().getOps().empty())
115  return;
116 
117  // Make the necessary modifications to each group's operations.
118  modifyGroupOperations(component);
119 
120  // Inline the body of each group.
121  inlineGroups(component);
122 
123  // Remove the last EnableOp from the control.
124  auto control = component.getControlOp();
125  control.walk([&](EnableOp enable) { enable->erase(); });
126 }
127 
128 std::unique_ptr<mlir::Pass> circt::calyx::createRemoveGroupsPass() {
129  return std::make_unique<RemoveGroupsPass>();
130 }
static void modifyGroupOperations(ComponentOp component)
Makes several modifications to the operations of a GroupOp:
void inlineGroups(ComponentOp component)
Inlines each group in the WiresOp.
static void updateGroupAssignmentGuards(OpBuilder &builder, GroupOp &group, Op &op)
Updates the guard of each assignment within a group with op.
Definition: CalyxHelpers.h:67
std::unique_ptr< mlir::Pass > createRemoveGroupsPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21