Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LLHD] Let WaitOp observe plain values instead of signals #7528

Merged
merged 1 commit into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/circt/Dialect/LLHD/IR/LLHDStructureOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,14 @@ def WaitOp : LLHDOp<"wait", [
```
}];

let arguments = (ins Variadic<InOutType>:$obs,
let arguments = (ins Variadic<HWValueType>:$observed,
Optional<LLHDTimeType>:$time,
Variadic<AnyType>:$destOps);

let successors = (successor AnySuccessor:$dest);

let assemblyFormat = [{
(`for` $time^ `,`)? (`(`$obs^ `:` qualified(type($obs))`)` `,`)?
(`for` $time^ `,`)? (`(`$observed^ `:` qualified(type($observed))`)` `,`)?
$dest (`(` $destOps^ `:` qualified(type($destOps)) `)`)? attr-dict
}];
}
Expand Down
21 changes: 19 additions & 2 deletions lib/Conversion/MooreToCore/MooreToCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,19 @@ struct WaitEventOpConversion : public OpConversionPattern<WaitEventOp> {
rewriter.eraseOp(detectOp);
}

auto setInsertionPointAfterDef = [&](Value value) {
if (auto *op = value.getDefiningOp())
rewriter.setInsertionPointAfter(op);
if (auto arg = dyn_cast<BlockArgument>(value))
rewriter.setInsertionPointToStart(value.getParentBlock());
};

auto probeIfSignal = [&](Value value) -> Value {
if (!isa<hw::InOutType>(value.getType()))
return value;
return rewriter.create<llhd::PrbOp>(loc, value);
};

// Determine the values used during event detection that are defined outside
// the `wait_event`'s body region. We want to wait for a change on these
// signals before we check if any interesting event happened.
Expand All @@ -334,12 +347,16 @@ struct WaitEventOpConversion : public OpConversionPattern<WaitEventOp> {
if (!alreadyObserved.insert(value).second)
continue;
if (auto remapped = rewriter.getRemappedValue(value)) {
observeValues.push_back(remapped);
OpBuilder::InsertionGuard g(rewriter);
setInsertionPointAfterDef(remapped);
observeValues.push_back(probeIfSignal(remapped));
} else {
OpBuilder::InsertionGuard g(rewriter);
setInsertionPointAfterDef(value);
auto type = typeConverter->convertType(value.getType());
auto converted = typeConverter->materializeTargetConversion(
rewriter, loc, type, value);
observeValues.push_back(converted);
observeValues.push_back(probeIfSignal(converted));
}
}
});
Expand Down
55 changes: 16 additions & 39 deletions lib/Dialect/LLHD/Transforms/ProcessLoweringPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,40 +34,6 @@ struct ProcessLoweringPass
void runOnOperation() override;
};

/// Backtrack a signal value and make sure that every part of it is in the
/// observer list at some point. Assumes that there is no operation that adds
/// parts to a signal that it does not take as input (e.g. something like
/// llhd.sig.zext %sig : !hw.inout<i32> -> !hw.inout<i64>).
static LogicalResult checkSignalsAreObserved(OperandRange obs, Value value) {
// If the value in the observer list, we don't need to backtrack further.
if (llvm::is_contained(obs, value))
return success();

if (Operation *op = value.getDefiningOp()) {
// If no input is a signal, this operation creates one and thus this is the
// last point where it could have been observed. As we've already checked
// that, we can fail here. This includes for example llhd.sig
if (llvm::none_of(op->getOperands(), [](Value arg) {
return isa<hw::InOutType>(arg.getType());
}))
return failure();

// Only recusively backtrack signal values. Other values cannot be changed
// from outside or with a delay. If they come from probes at some point,
// they are covered by that probe. As soon as we find a signal that is not
// observed no matter how far we backtrack, we fail.
return success(llvm::all_of(op->getOperands(), [&](Value arg) {
return !isa<hw::InOutType>(arg.getType()) ||
succeeded(checkSignalsAreObserved(obs, arg));
}));
}

// If the value is a module argument (no block arguments except for the entry
// block are allowed here) and was not observed, we cannot backtrack further
// and thus fail.
return failure();
}

static LogicalResult isProcValidToLower(llhd::ProcessOp op) {
size_t numBlocks = op.getBody().getBlocks().size();

Expand Down Expand Up @@ -98,13 +64,24 @@ static LogicalResult isProcValidToLower(llhd::ProcessOp op) {
"during process-lowering: llhd.wait terminators with optional time "
"argument cannot be lowered to structural LLHD");

SmallVector<Value> observedSignals;
for (Value obs : wait.getObserved())
if (auto prb = obs.getDefiningOp<llhd::PrbOp>())
if (!op.getBody().isAncestor(prb->getParentRegion()))
observedSignals.push_back(prb.getSignal());

// Every probed signal has to occur in the observed signals list in
// the wait instruction
WalkResult result = op.walk([&wait](llhd::PrbOp prbOp) -> WalkResult {
if (failed(checkSignalsAreObserved(wait.getObs(), prbOp.getSignal())))
return wait.emitOpError(
"during process-lowering: the wait terminator is required to "
"have all probed signals as arguments");
WalkResult result = op.walk([&](Operation *operation) -> WalkResult {
// TODO: value does not need to be observed if all values this value is
// a combinatorial result of are observed.
for (Value operand : operation->getOperands())
if (!op.getBody().isAncestor(operand.getParentRegion()) &&
!llvm::is_contained(wait.getObserved(), operand) &&
!llvm::is_contained(observedSignals, operand))
return wait.emitOpError(
"during process-lowering: the wait terminator is required to "
"have values used in the process as arguments");

return WalkResult::advance();
});
Expand Down
25 changes: 18 additions & 7 deletions test/Conversion/MooreToCore/basic.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -536,8 +536,19 @@ func.func private @dummyC() -> ()
// CHECK-LABEL: hw.module @WaitEvent
moore.module @WaitEvent() {
// CHECK: %a = llhd.sig
// CHECK: [[PRB_A6:%.+]] = llhd.prb %a
// CHECK: [[PRB_A5:%.+]] = llhd.prb %a
// CHECK: [[PRB_A4:%.+]] = llhd.prb %a
// CHECK: [[PRB_A3:%.+]] = llhd.prb %a
// CHECK: [[PRB_A2:%.+]] = llhd.prb %a
// CHECK: [[PRB_A1:%.+]] = llhd.prb %a
// CHECK: [[PRB_A0:%.+]] = llhd.prb %a
// CHECK: %b = llhd.sig
// CHECK: [[PRB_B2:%.+]] = llhd.prb %b
// CHECK: [[PRB_B1:%.+]] = llhd.prb %b
// CHECK: [[PRB_B0:%.+]] = llhd.prb %b
// CHECK: %c = llhd.sig
// CHECK: [[PRB_C:%.+]] = llhd.prb %c
%a = moore.variable : <i1>
%b = moore.variable : <i1>
%c = moore.variable : <i1>
Expand Down Expand Up @@ -569,7 +580,7 @@ moore.module @WaitEvent() {
// CHECK: llhd.process {
moore.procedure initial {
// CHECK: [[BEFORE:%.+]] = llhd.prb %a
// CHECK: llhd.wait (%a : {{.+}}), ^[[CHECK:.+]]
// CHECK: llhd.wait ([[PRB_A0]] : {{.+}}), ^[[CHECK:.+]]
// CHECK: ^[[CHECK]]:
// CHECK: [[AFTER:%.+]] = llhd.prb %a
// CHECK: [[TMP:%.+]] = comb.icmp bin ne [[BEFORE]], [[AFTER]]
Expand All @@ -585,7 +596,7 @@ moore.module @WaitEvent() {
moore.procedure initial {
// CHECK: [[BEFORE_A:%.+]] = llhd.prb %a
// CHECK: [[BEFORE_B:%.+]] = llhd.prb %b
// CHECK: llhd.wait (%a, %b : {{.+}}), ^[[CHECK:.+]]
// CHECK: llhd.wait ([[PRB_A1]], [[PRB_B0]] : {{.+}}), ^[[CHECK:.+]]
// CHECK: ^[[CHECK]]:
// CHECK: [[AFTER_A:%.+]] = llhd.prb %a
// CHECK: [[AFTER_B:%.+]] = llhd.prb %b
Expand All @@ -605,7 +616,7 @@ moore.module @WaitEvent() {
// CHECK: [[BEFORE_A:%.+]] = llhd.prb %a
// CHECK: [[BEFORE_B:%.+]] = llhd.prb %b
// CHECK: [[BEFORE_C:%.+]] = llhd.prb %c
// CHECK: llhd.wait (%a, %b, %c : {{.+}}), ^[[CHECK:.+]]
// CHECK: llhd.wait ([[PRB_A2]], [[PRB_B1]], [[PRB_C]] : {{.+}}), ^[[CHECK:.+]]
// CHECK: ^[[CHECK]]:
// CHECK: [[AFTER_A:%.+]] = llhd.prb %a
// CHECK: [[AFTER_B:%.+]] = llhd.prb %b
Expand All @@ -629,7 +640,7 @@ moore.module @WaitEvent() {
// CHECK: llhd.process {
moore.procedure initial {
// CHECK: [[BEFORE:%.+]] = llhd.prb %a
// CHECK: llhd.wait (%a : {{.+}}), ^[[CHECK:.+]]
// CHECK: llhd.wait ([[PRB_A3]] : {{.+}}), ^[[CHECK:.+]]
// CHECK: ^[[CHECK]]:
// CHECK: [[AFTER:%.+]] = llhd.prb %a
// CHECK: [[TRUE:%.+]] = hw.constant true
Expand All @@ -646,7 +657,7 @@ moore.module @WaitEvent() {
// CHECK: llhd.process {
moore.procedure initial {
// CHECK: [[BEFORE:%.+]] = llhd.prb %a
// CHECK: llhd.wait (%a : {{.+}}), ^[[CHECK:.+]]
// CHECK: llhd.wait ([[PRB_A4]] : {{.+}}), ^[[CHECK:.+]]
// CHECK: ^[[CHECK]]:
// CHECK: [[AFTER:%.+]] = llhd.prb %a
// CHECK: [[TRUE:%.+]] = hw.constant true
Expand All @@ -663,7 +674,7 @@ moore.module @WaitEvent() {
// CHECK: llhd.process {
moore.procedure initial {
// CHECK: [[BEFORE:%.+]] = llhd.prb %a
// CHECK: llhd.wait (%a : {{.+}}), ^[[CHECK:.+]]
// CHECK: llhd.wait ([[PRB_A5]] : {{.+}}), ^[[CHECK:.+]]
// CHECK: ^[[CHECK]]:
// CHECK: [[AFTER:%.+]] = llhd.prb %a
// CHECK: [[TRUE:%.+]] = hw.constant true
Expand All @@ -682,7 +693,7 @@ moore.module @WaitEvent() {

// CHECK: llhd.process {
moore.procedure initial {
// CHECK: llhd.wait (%a, %b :
// CHECK: llhd.wait ([[PRB_A6]], [[PRB_B2]] :
moore.wait_event {
%0 = moore.constant 0 : i1
%1 = moore.conditional %0 : i1 -> i1 {
Expand Down
5 changes: 3 additions & 2 deletions test/Dialect/LLHD/Canonicalization/probeCSE.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@ hw.module @checkPrbDceAndCseIn(inout %arg0 : i32, inout %arg1 : i32, inout %arg2

// CHECK-LABEL: @checkPrbDceButNotCse
hw.module @checkPrbDceButNotCse(inout %arg0 : i32, inout %arg1 : i32, inout %arg2 : i32) {
// CHECK-NEXT: llhd.process
%prb = llhd.prb %arg0 : !hw.inout<i32>
// CHECK: llhd.process
llhd.process {
// CHECK-NEXT: llhd.constant_time
%time = llhd.constant_time <0ns, 1d, 0e>

// CHECK-NEXT: [[P1:%.*]] = llhd.prb
%1 = llhd.prb %arg0 : !hw.inout<i32>
// CHECK-NEXT: llhd.wait
llhd.wait (%arg0: !hw.inout<i32>), ^bb1
llhd.wait (%prb: i32), ^bb1
// CHECK-NEXT: ^bb1:
^bb1:
// CHECK-NEXT: [[P2:%.*]] = llhd.prb
Expand Down
16 changes: 12 additions & 4 deletions test/Dialect/LLHD/IR/basic.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,14 @@ hw.module @check_wait_1 () {

// CHECK: @check_wait_2(inout %[[ARG0:.*]] : i64, inout %[[ARG1:.*]] : i1) {
hw.module @check_wait_2 (inout %arg0 : i64, inout %arg1 : i1) {
// CHECK: [[PRB0:%.+]] = llhd.prb %arg0
%prb0 = llhd.prb %arg0 : !hw.inout<i64>
// CHECK: [[PRB1:%.+]] = llhd.prb %arg1
%prb1 = llhd.prb %arg1 : !hw.inout<i1>
// CHECK-NEXT: llhd.process
llhd.process {
// CHECK-NEXT: llhd.wait (%[[ARG0]], %[[ARG1]] : !hw.inout<i64>, !hw.inout<i1>), ^[[BB:.*]](%[[ARG1]] : !hw.inout<i1>)
llhd.wait (%arg0, %arg1 : !hw.inout<i64>, !hw.inout<i1>), ^bb1(%arg1 : !hw.inout<i1>)
// CHECK-NEXT: llhd.wait ([[PRB0]], [[PRB1]] : i64, i1), ^[[BB:.*]](%[[ARG1]] : !hw.inout<i1>)
llhd.wait (%prb0, %prb1 : i64, i1), ^bb1(%arg1 : !hw.inout<i1>)
// CHECK: ^[[BB]](%[[A:.*]]: !hw.inout<i1>):
^bb1(%a: !hw.inout<i1>):
llhd.halt
Expand All @@ -188,12 +192,16 @@ hw.module @check_wait_2 (inout %arg0 : i64, inout %arg1 : i1) {

// CHECK: hw.module @check_wait_3(inout %[[ARG0:.*]] : i64, inout %[[ARG1:.*]] : i1) {
hw.module @check_wait_3 (inout %arg0 : i64, inout %arg1 : i1) {
// CHECK: [[PRB0:%.+]] = llhd.prb %arg0
%prb0 = llhd.prb %arg0 : !hw.inout<i64>
// CHECK: [[PRB1:%.+]] = llhd.prb %arg1
%prb1 = llhd.prb %arg1 : !hw.inout<i1>
// CHECK-NEXT: llhd.process
llhd.process {
// CHECK-NEXT: %[[TIME:.*]] = llhd.constant_time
%time = llhd.constant_time #llhd.time<0ns, 0d, 0e>
// CHECK-NEXT: llhd.wait for %[[TIME]], (%[[ARG0]], %[[ARG1]] : !hw.inout<i64>, !hw.inout<i1>), ^[[BB:.*]](%[[ARG1]], %[[ARG0]] : !hw.inout<i1>, !hw.inout<i64>)
llhd.wait for %time, (%arg0, %arg1 : !hw.inout<i64>, !hw.inout<i1>), ^bb1(%arg1, %arg0 : !hw.inout<i1>, !hw.inout<i64>)
// CHECK-NEXT: llhd.wait for %[[TIME]], ([[PRB0]], [[PRB1]] : i64, i1), ^[[BB:.*]](%[[ARG1]], %[[ARG0]] : !hw.inout<i1>, !hw.inout<i64>)
llhd.wait for %time, (%prb0, %prb1 : i64, i1), ^bb1(%arg1, %arg0 : !hw.inout<i1>, !hw.inout<i64>)
// CHECK: ^[[BB]](%[[A:.*]]: !hw.inout<i1>, %[[B:.*]]: !hw.inout<i64>):
^bb1(%a: !hw.inout<i1>, %b: !hw.inout<i64>):
llhd.halt
Expand Down
14 changes: 10 additions & 4 deletions test/Dialect/LLHD/Transforms/earlyCodeMotion.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ hw.module @check_blockarg(inout %sig : i32) {

// CHECK-LABEL: @loop
// CHECK-SAME: (inout %[[VAL_0:.*]] : i2)
// CHECK: [[PRB:%.+]] = llhd.prb %in_i
// CHECK: llhd.process
// CHECK: %[[VAL_1:.*]] = hw.constant 0 : i32
// CHECK: %[[VAL_2:.*]] = hw.constant 2 : i32
Expand All @@ -138,14 +139,15 @@ hw.module @check_blockarg(inout %sig : i32) {
// CHECK: %[[VAL_8:.*]] = llhd.prb %[[VAL_0]] : !hw.inout<i2>
// CHECK: cf.cond_br %[[VAL_7]], ^[[BB4:.+]], ^[[BB3:.+]]
// CHECK: ^[[BB3]]:
// CHECK: llhd.wait (%[[VAL_0]] : !hw.inout<i2>), ^[[BB1]]
// CHECK: llhd.wait ([[PRB]] : i2), ^[[BB1]]
// CHECK: ^[[BB4]]:
// CHECK: %[[VAL_9:.*]] = llhd.load %[[VAL_5]] : !llhd.ptr<i32>
// CHECK: %[[VAL_10:.*]] = comb.add %[[VAL_9]], %[[VAL_4]] : i32
// CHECK: llhd.store %[[VAL_5]], %[[VAL_10]] : !llhd.ptr<i32>
// CHECK: cf.br ^[[BB2]]
// CHECK: }
hw.module @loop(inout %in_i : i2) {
%prb0 = llhd.prb %in_i : !hw.inout<i2>
llhd.process {
// TR: -1
cf.br ^body
Expand All @@ -162,7 +164,7 @@ hw.module @loop(inout %in_i : i2) {
cf.cond_br %2, ^loop_continue, ^check
^check:
// TR: 1
llhd.wait (%in_i : !hw.inout<i2>), ^body
llhd.wait (%prb0 : i2), ^body
^loop_continue:
// TR: 1
%3 = hw.constant 0 : i2
Expand All @@ -177,6 +179,8 @@ hw.module @loop(inout %in_i : i2) {

// CHECK-LABEL: @complicated
// CHECK-SAME: (inout %[[VAL_0:.*]] : i1, inout %[[VAL_1:.*]] : i1, inout %[[VAL_2:.*]] : i1, inout %[[VAL_3:.*]] : i1, inout %[[VAL_4:.*]] : i1)
// CHECK: [[PRB_CLK:%.+]] = llhd.prb %[[VAL_1]]
// CHECK: [[PRB_RST:%.+]] = llhd.prb %[[VAL_0]]
// CHECK: llhd.process
// CHECK: %[[ALLSET:.*]] = hw.constant true
// CHECK: %[[VAL_5:.*]] = hw.constant false
Expand All @@ -191,7 +195,7 @@ hw.module @loop(inout %in_i : i2) {
// CHECK: %[[VAL_10:.*]] = llhd.prb %[[VAL_0]] : !hw.inout<i1>
// CHECK: %[[VAL_11:.*]] = comb.icmp eq %[[VAL_9]], %[[VAL_5]] : i1
// CHECK: %[[VAL_12:.*]] = comb.icmp ne %[[VAL_10]], %[[VAL_5]] : i1
// CHECK: llhd.wait (%[[VAL_1]], %[[VAL_0]] : !hw.inout<i1>, !hw.inout<i1>), ^[[BB3:.+]]
// CHECK: llhd.wait ([[PRB_CLK]], [[PRB_RST]] : i1, i1), ^[[BB3:.+]]
// CHECK: ^[[BB3]]:
// CHECK: %[[VAL_13:.*]] = llhd.prb %[[VAL_3]] : !hw.inout<i1>
// CHECK: llhd.store %[[VAL_8]], %[[VAL_13]] : !llhd.ptr<i1>
Expand Down Expand Up @@ -221,6 +225,8 @@ hw.module @loop(inout %in_i : i2) {
// CHECK: cf.br ^[[BB1]]
// CHECK: }
hw.module @complicated(inout %rst_ni: i1, inout %clk_i: i1, inout %async_ack_i: i1, inout %ack_src_q: i1, inout %ack_q: i1) {
%prb_clk = llhd.prb %clk_i : !hw.inout<i1>
%prb_rst = llhd.prb %rst_ni : !hw.inout<i1>
llhd.process {
%allset = hw.constant 1 : i1
// TR: -1
Expand All @@ -234,7 +240,7 @@ hw.module @complicated(inout %rst_ni: i1, inout %clk_i: i1, inout %async_ack_i:
// TR: 2
%clk_i_prb = llhd.prb %clk_i : !hw.inout<i1>
%rst_ni_prb = llhd.prb %rst_ni : !hw.inout<i1>
llhd.wait (%clk_i, %rst_ni : !hw.inout<i1>, !hw.inout<i1>), ^check
llhd.wait (%prb_clk, %prb_rst : i1, i1), ^check
^check:
// TR: 0
%2 = llhd.prb %ack_src_q : !hw.inout<i1>
Expand Down
6 changes: 4 additions & 2 deletions test/Dialect/LLHD/Transforms/memoryToBlockArgument.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ hw.module @multiple_store_one_block() {

// CHECK-LABEL: @loop
// CHECK-SAME: (inout %[[VAL_0:.*]] : i2)
// CHECK: [[PRB:%.+]] = llhd.prb %[[VAL_0]]
// CHECK: cf.br ^bb1
// CHECK: ^bb1:
// CHECK: %[[VAL_1:.*]] = hw.constant 0 : i32
Expand All @@ -271,14 +272,15 @@ hw.module @multiple_store_one_block() {
// CHECK: %[[VAL_4:.*]] = comb.icmp ult %[[VAL_2]], %[[VAL_3]] : i32
// CHECK: cf.cond_br %[[VAL_4]], ^bb4, ^bb3
// CHECK: ^bb3:
// CHECK: llhd.wait (%[[VAL_0]] : !hw.inout<i2>), ^bb1
// CHECK: llhd.wait ([[PRB]] : i2), ^bb1
// CHECK: ^bb4:
// CHECK: %[[VAL_5:.*]] = hw.constant 0 : i2
// CHECK: %[[VAL_6:.*]] = hw.constant 1 : i32
// CHECK: %[[VAL_7:.*]] = comb.add %[[VAL_2]], %[[VAL_6]] : i32
// CHECK: cf.br ^bb2(%[[VAL_7]] : i32)
// CHECK: }
hw.module @loop(inout %in_i : i2) {
%prb = llhd.prb %in_i : !hw.inout<i2>
llhd.process {
cf.br ^body
^body:
Expand All @@ -291,7 +293,7 @@ hw.module @loop(inout %in_i : i2) {
%2 = comb.icmp ult %i_ld, %1 : i32
cf.cond_br %2, ^loop_continue, ^check
^check:
llhd.wait (%in_i : !hw.inout<i2>), ^body
llhd.wait (%prb : i2), ^body
^loop_continue:
%3 = hw.constant 0 : i2
%5 = hw.constant 1 : i32
Expand Down
Loading
Loading