Skip to content

Commit 3ecbcc1

Browse files
committed
impl branch interface in wait op, use simplify region, adapt tests
1 parent c46ae8c commit 3ecbcc1

File tree

4 files changed

+62
-122
lines changed

4 files changed

+62
-122
lines changed

include/circt/Dialect/LLHD/IR/LLHDStructureOps.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ def WaitOp : LLHDOp<"wait", [
144144
AttrSizedOperandSegments,
145145
HasParent<"ProcessOp">,
146146
Terminator,
147+
DeclareOpInterfaceMethods<BranchOpInterface, ["getSuccessorForOperands"]>
147148
]> {
148149
let summary = "Suspend execution of a process";
149150
let description = [{

lib/Dialect/LLHD/IR/LLHDOps.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,15 @@ static LogicalResult verifyYieldResults(Operation *op,
546546
return success();
547547
}
548548

549+
SuccessorOperands WaitOp::getSuccessorOperands(unsigned index) {
550+
assert(index == 0 && "invalid successor index");
551+
return SuccessorOperands(getDestOperandsMutable());
552+
}
553+
554+
Block *WaitOp::getSuccessorForOperands(ArrayRef<Attribute>) {
555+
return getDest();
556+
}
557+
549558
LogicalResult WaitOp::verify() {
550559
return verifyYieldResults(*this, getYieldOperands());
551560
}

lib/Dialect/LLHD/Transforms/LowerProcesses.cpp

Lines changed: 26 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -288,116 +288,39 @@ struct LowerProcessesPass
288288
void runOnOperation() override;
289289
};
290290

291-
static std::optional<DenseMap<BlockArgument, Value>>
292-
getBlockArgsToPrune(Block &block) {
293-
DenseMap<BlockArgument, Value> result;
294-
SmallPtrSet<Value, 4> branchOperands;
295-
296-
for (auto &arg : block.getArguments()) {
297-
for (auto it = block.pred_begin(); it != block.pred_end(); ++it) {
298-
Block *predecessor = *it;
299-
if (auto branchOp =
300-
dyn_cast<BranchOpInterface>(predecessor->getTerminator())) {
301-
SuccessorOperands successorOperands =
302-
branchOp.getSuccessorOperands(it.getSuccessorIndex());
303-
304-
if (Value operand = successorOperands[arg.getArgNumber()]) {
305-
branchOperands.insert(operand);
306-
} else {
307-
return {};
308-
}
309-
} else if (auto waitOp = dyn_cast<WaitOp>(predecessor->getTerminator())) {
310-
auto destOperands = waitOp.getDestOperands();
311-
branchOperands.insert(destOperands[arg.getArgNumber()]);
312-
} else {
313-
return {};
314-
}
315-
}
316-
317-
if (branchOperands.size() == 1) {
318-
result.insert(std::make_pair(arg, *branchOperands.begin()));
319-
}
320-
321-
branchOperands.clear();
322-
}
323-
324-
return result;
325-
}
326-
327-
static bool simplifyBlocksArgs(ProcessOp &processOp) {
328-
SmallVector<Block *> worklist;
329-
for (auto &block : processOp.getBody()) {
330-
auto waitOp = dyn_cast<WaitOp>(block.getTerminator());
331-
if (!waitOp)
332-
continue;
333-
334-
auto dstOperands = waitOp.getDestOperands();
335-
if (dstOperands.empty())
336-
continue;
337-
338-
if (llvm::none_of(dstOperands,
339-
[](auto operand) { return isa<BlockArgument>(operand); }))
340-
continue;
341-
342-
worklist.push_back(&block);
343-
}
344-
345-
while (!worklist.empty()) {
346-
auto *block = worklist.pop_back_val();
347-
auto blockArgsToPrune = getBlockArgsToPrune(*block);
348-
if (!blockArgsToPrune.has_value() || blockArgsToPrune->empty())
349-
continue;
350-
351-
llvm::BitVector argsToErase(block->getNumArguments());
352-
for (auto &[blockArg, replaceValue] : *blockArgsToPrune) {
353-
LLVM_DEBUG(llvm::dbgs()
354-
<< "replace" << blockArg << " with " << replaceValue << "\n");
355-
356-
argsToErase.set(blockArg.getArgNumber());
357-
}
358-
359-
auto argNums = llvm::to_vector(argsToErase.set_bits());
360-
for (auto it = block->pred_begin(); it != block->pred_end(); ++it) {
361-
Block *predecessor = *it;
362-
if (auto branchOp =
363-
dyn_cast<BranchOpInterface>(predecessor->getTerminator())) {
364-
SuccessorOperands successorOperands =
365-
branchOp.getSuccessorOperands(it.getSuccessorIndex());
366-
367-
const auto argOff = successorOperands.getProducedOperandCount();
368-
for (const auto argNum : llvm::reverse(argNums)) {
369-
int start = argOff + argNum;
370-
successorOperands.erase(start);
371-
}
372-
} else if (auto waitOp = dyn_cast<WaitOp>(predecessor->getTerminator())) {
373-
auto destOperands = waitOp.getDestOperandsMutable();
374-
for (const auto argNum : llvm::reverse(argNums)) {
375-
destOperands.erase(argNum);
376-
}
377-
} else {
378-
llvm_unreachable("Unexpected predecessor terminator");
379-
}
380-
}
381-
382-
for (auto &[blockArg, replaceValue] : *blockArgsToPrune) {
383-
blockArg.replaceAllUsesWith(replaceValue);
384-
}
385-
386-
block->eraseArguments(argsToErase);
387-
388-
for (auto *successor : block->getSuccessors())
389-
worklist.push_back(successor);
390-
}
391-
392-
return true;
291+
// Perform cleanup on the process operation prior to lowering.
292+
// This can remove redundant operands passed to the successor of llhd.wait.
293+
//
294+
// ^bb0
295+
// cf.br ^bb1(%clock : i1)
296+
// ^bb1(%1: i1): // pred: ^bb0, ^bb2
297+
// llhd.wait yield (...), (%clock : i1), ^bb2(%1 : i1)
298+
// ^bb2(%2: i1): // pred: ^bb1
299+
// cf.cond_br %true, ^bb3, ^bb1(%2 : i1)
300+
// ^bb3:
301+
//
302+
// The above IR can be rewritten as:
303+
//
304+
// ^bb0
305+
// cf.br ^bb1
306+
// ^bb1: // pred: ^bb0, ^bb2
307+
// llhd.wait yield (...), (%clock : i1), ^bb2
308+
// ^bb2: // pred: ^bb1
309+
// cf.cond_br %true, ^bb3, ^bb1
310+
// ^bb3:
311+
//
312+
static void simplifyProcess(ProcessOp &processOp) {
313+
OpBuilder builder(processOp);
314+
IRRewriter rewriter(builder);
315+
(void)simplifyRegions(rewriter, processOp->getRegions());
393316
}
394317

395318
} // namespace
396319

397320
void LowerProcessesPass::runOnOperation() {
398321
SmallVector<ProcessOp> processOps(getOperation().getOps<ProcessOp>());
399322
for (auto processOp : processOps) {
400-
simplifyBlocksArgs(processOp);
323+
simplifyProcess(processOp);
401324
Lowering(processOp).lower();
402325
}
403326
}

test/Dialect/LLHD/Transforms/lower-processes.mlir

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -158,50 +158,57 @@ hw.module @SkipIfNoWaits() {
158158
}
159159

160160
// CHECK-LABEL: @SkipIfWaitHasDestinationOperands(
161-
hw.module @SkipIfWaitHasDestinationOperands(in %a: i42) {
161+
hw.module @SkipIfWaitHasDestinationOperands(in %a: i42, in %b: i42) {
162162
// CHECK: llhd.process
163-
llhd.process {
164-
cf.br ^bb1
165-
^bb1:
166-
llhd.wait ^bb2(%a : i42)
167-
^bb2(%0: i42):
168-
cf.br ^bb1
163+
// CHECK: llhd.wait yield ({{.*}} : i42), ^bb2({{.*}} : i42)
164+
%0 = llhd.process -> i42 {
165+
cf.br ^bb1(%a : i42)
166+
^bb1(%1: i42):
167+
%false = hw.constant false
168+
%c100 = hw.constant 100 : i42
169+
cf.cond_br %false, ^bb2(%1 : i42), ^bb3(%c100 : i42)
170+
^bb2(%2: i42):
171+
llhd.wait yield (%2 : i42), ^bb2(%2 : i42)
172+
^bb3(%3: i42):
173+
%4 = comb.add %3, %b : i42
174+
cf.br ^bb1(%4 : i42)
169175
}
170176
}
171177

172178
// CHECK-LABEL: @SkipIfEntryAndWaitConvergeInWrongSpot(
173179
hw.module @SkipIfEntryAndWaitConvergeInWrongSpot(in %a: i42) {
174180
// CHECK: llhd.process
181+
%c100 = hw.constant 100 : i42
175182
llhd.process {
176-
cf.br ^bb2 // skip logic after wait
183+
cf.br ^bb2(%c100 : i42)
177184
^bb1:
178185
%0 = comb.add %a, %a : i42
179-
cf.br ^bb2
180-
^bb2:
181-
llhd.wait ^bb1
186+
cf.br ^bb2(%0 : i42)
187+
^bb2(%1 : i42):
188+
llhd.wait (%1 : i42), ^bb1
182189
}
183190
}
184191

185192
// CHECK-LABEL: @SkipIfEntryAndWaitConvergeWithDifferentBlockArgs(
186193
hw.module @SkipIfEntryAndWaitConvergeWithDifferentBlockArgs(in %a: i42, in %b: i42) {
187194
// CHECK: llhd.process
188-
llhd.process {
195+
%0 = llhd.process -> i42 {
189196
cf.br ^bb2(%a : i42)
190197
^bb1:
191198
cf.br ^bb2(%b : i42)
192199
^bb2(%0: i42):
193-
llhd.wait ^bb1
200+
llhd.wait yield (%0 : i42), ^bb1
194201
}
195202
}
196203

197204
// CHECK-LABEL: @SkipIfValueUnobserved(
198205
hw.module @SkipIfValueUnobserved(in %a: i42) {
199206
// CHECK: llhd.process
200-
llhd.process {
207+
%0 = llhd.process -> i42 {
201208
cf.br ^bb1
202209
^bb1:
203210
%0 = comb.add %a, %a : i42
204-
llhd.wait ^bb1
211+
llhd.wait yield (%0 : i42), ^bb1
205212
}
206213
}
207214

@@ -246,19 +253,19 @@ hw.module @PruneWaitOperands(in %clock : i1, in %f1 : i2, in %f2 : i3) {
246253
%c100_i10 = hw.constant 100 : i10
247254
%c110_i10 = hw.constant 110 : i10
248255
%true = hw.constant true
249-
// CHECK: llhd.process -> i1 {
256+
// CHECK: llhd.process -> i1, i8, i2, i10, i3 {
250257
// CHECK-NEXT: cf.br ^bb1(%c10_i8, %c100_i10 : i8, i10)
251258
// CHECK-NEXT: ^bb1(%1: i8, %2: i10):
252-
// CHECK-NEXT: llhd.wait yield (%false : i1), (%clock : i1), ^bb2
259+
// CHECK-NEXT: llhd.wait yield (%clock, %1, %f1, %2, %f2 : i1, i8, i2, i10, i3), (%clock : i1), ^bb2
253260
// CHECK-NEXT: ^bb2:
254261
// CHECK: cf.cond_br {{.*}}, ^bb3, ^bb1(%c20_i8, %c110_i10 : i8, i10)
255262
// CHECK-NEXT: ^bb3:
256263
// CHECK: cf.cond_br {{.*}}, ^bb1(%c10_i8, %c100_i10 : i8, i10), ^bb1(%c20_i8, %c110_i10 : i8, i10)
257264
// CHECK-NEXT: }
258-
%0 = llhd.process -> i1 {
265+
%0:5 = llhd.process -> i1, i8, i2, i10, i3 {
259266
cf.br ^bb1(%clock, %c10_i8, %f1, %c100_i10, %f2 : i1, i8, i2, i10, i3)
260267
^bb1(%1: i1, %2: i8, %3: i2, %4: i10, %5: i3):
261-
llhd.wait yield (%false : i1), (%clock : i1), ^bb2(%2, %1, %3, %5, %4 : i8, i1, i2, i3, i10)
268+
llhd.wait yield (%1, %2, %3, %4, %5 : i1, i8, i2, i10, i3), (%clock : i1), ^bb2(%2, %1, %3, %5, %4 : i8, i1, i2, i3, i10)
262269
^bb2(%6: i8, %7: i1, %8: i2, %9: i3, %10: i10):
263270
%15 = comb.xor bin %7, %true : i1
264271
%16 = comb.and bin %15, %clock : i1

0 commit comments

Comments
 (0)