Skip to content

Refactor the dataflow mode logic#121

Merged
ShangkunLi merged 3 commits intocoredac:mainfrom
ShangkunLi:fix-action
Aug 25, 2025
Merged

Refactor the dataflow mode logic#121
ShangkunLi merged 3 commits intocoredac:mainfrom
ShangkunLi:fix-action

Conversation

@ShangkunLi
Copy link
Copy Markdown
Collaborator

Many thanks for the code base built by @itemkelvin~! Fix some bugs in this pr.

In the previous dataflow mode interpreter, it doesn't respect the topological order of operations, triggering operations based on value update. This may result in executing consumers before producers. For example, for the following simple loop. It should output 15.00000.

func.func @loop_sum() -> f32 attributes {accelerator = "neura"} {
    %0 = "neura.grant_once"() <{constant_value = 0.000000e+00 : f32}> : () -> !neura.data<f32, i1>
    %1 = "neura.grant_once"() <{constant_value = 1.000000e+00 : f32}> : () -> !neura.data<f32, i1>
    %2 = "neura.grant_once"() <{constant_value = 3.000000e+00 : f32}> : () -> !neura.data<f32, i1>
    %3 = "neura.grant_once"() <{constant_value = 5.000000e+00 : f32}> : () -> !neura.data<f32, i1>
    %4 = neura.reserve : !neura.data<f32, i1>
    %5 = "neura.phi"(%4, %1) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %6 = neura.reserve : !neura.data<f32, i1>
    %7 = "neura.phi"(%6, %2) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %8 = neura.reserve : !neura.data<f32, i1>
    %9 = "neura.phi"(%8, %3) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %10 = neura.reserve : !neura.data<f32, i1>
    %11 = "neura.phi"(%10, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %12 = neura.reserve : !neura.data<f32, i1>
    %13 = "neura.phi"(%12, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %14 = "neura.fcmp"(%13, %9) <{cmpType = "lt"}> : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<i1, i1>
    %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %16 = neura.grant_predicate %11, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %17 = neura.grant_predicate %7, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %18 = neura.grant_predicate %5, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %19 = neura.grant_predicate %9, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %20 = "neura.not"(%14) : (!neura.data<i1, i1>) -> !neura.data<i1, i1>
    %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    neura.ctrl_mov %23 -> %12 : !neura.data<f32, i1> !neura.data<f32, i1>
    neura.ctrl_mov %22 -> %10 : !neura.data<f32, i1> !neura.data<f32, i1>
    neura.ctrl_mov %19 -> %8 : !neura.data<f32, i1> !neura.data<f32, i1>
    neura.ctrl_mov %17 -> %6 : !neura.data<f32, i1> !neura.data<f32, i1>
    neura.ctrl_mov %18 -> %4 : !neura.data<f32, i1> !neura.data<f32, i1>
    "neura.return"(%21) : (!neura.data<f32, i1>) -> ()
  }

In the previous implementation, %14 will execute after %15 and %16 because of the update-based operation triggering. And it cannot handle the return operations properly, thus outputting both

[neura-interpreter]  Executing operation: "neura.return"(%21) : (!neura.data<f32, i1>) -> ()
[neura-interpreter]  Executing neura.return:
[neura-interpreter]  ├─ Return values:
[neura-interpreter]  │  └─15.000000, [pred = 1]
[neura-interpreter]  └─ Execution terminated successfully

and

[neura-interpreter]  Executing operation: "neura.return"(%21) : (!neura.data<f32, i1>) -> ()
[neura-interpreter]  Executing neura.return:
[neura-interpreter]  ├─ Return values:
[neura-interpreter]  │  └─18.000000, [pred = 1]
[neura-interpreter]  └─ Execution terminated successfully

.

In this pr, we introduce two features:

  • DFG resetting/switching enables iteratively executing a DFG for different loop iterations until we get a valid return value
  • Topologically executing each operation in a DFG that respects the producer-consumer relationship

@ShangkunLi ShangkunLi self-assigned this Aug 24, 2025
@ShangkunLi ShangkunLi marked this pull request as ready for review August 24, 2025 15:01
@tancheng
Copy link
Copy Markdown
Contributor

Thanks @ShangkunLi,

DFG resetting/switching enables iteratively executing a DFG for different loop iterations until we get a valid return value

Why we need this? It sounds different iterations are simultaneously executing, isn't it a mess? Shouldn't it be iter by iter (though this is not dataflow's convention)? In other words, for dataflow, there shouldn't be "iter" concept, we are iterating ready_to_execute_ops based on dependency and is_udpated, right?

Topologically executing each operation in a DFG that respects the producer-consumer relationship

@itemkelvin and I discussed topological ordering, and he did start from independent ops as follows, why it doesn't help?
https://github.com/coredac/dataflow/blob/7502a4586793094caf18d04b01db23df6b96887b/tools/neura-interpreter/neura-interpreter.cpp#L2997

And a general comment:

  • You format re-factoring always put some burden on my review process (i.e., tons of not-related changes/modifications).. Can you not change the format when you implement new things? You can always have a separate PR purely for refactoring before or after your implementation PR, how does it sound~!

@itemkelvin
Copy link
Copy Markdown
Collaborator

itemkelvin commented Aug 25, 2025 via email

@ShangkunLi
Copy link
Copy Markdown
Collaborator Author

@itemkelvin and I discussed topological ordering, and he did start from independent ops as follows, why it doesn't help?

https://github.com/coredac/dataflow/blob/7502a4586793094caf18d04b01db23df6b96887b/tools/neura-interpreter/neura-interpreter.cpp#L2997

Because in previous implementation, it only respect the topological order in findIndependentInSequence(). After that, the execution of new operations is based on value update. For example, we trigger %15 when %13 is updated and %14 is ready.

The bug is: when all the consumer of %14 in the first loop/DFG iteration are finished, %14 is not set to invalid. When we execute the next loop iteration, %13 is updated and it triggers %15, and %15 finds that %14 is also valid (this is the bug, because the valid %14 belongs to the last loop iteration). Then %15 of this loop iteration is executed before %14, which violates the topological order exeuction.

  func.func @loop_sum() -> f32 attributes {accelerator = "neura"} {
    %0 = "neura.grant_once"() <{constant_value = 0.000000e+00 : f32}> : () -> !neura.data<f32, i1>
    %1 = "neura.grant_once"() <{constant_value = 1.000000e+00 : f32}> : () -> !neura.data<f32, i1>
    %2 = "neura.grant_once"() <{constant_value = 3.000000e+00 : f32}> : () -> !neura.data<f32, i1>
    %3 = "neura.grant_once"() <{constant_value = 5.000000e+00 : f32}> : () -> !neura.data<f32, i1>
    %4 = neura.reserve : !neura.data<f32, i1>
    %5 = "neura.phi"(%4, %1) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %6 = neura.reserve : !neura.data<f32, i1>
    %7 = "neura.phi"(%6, %2) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %8 = neura.reserve : !neura.data<f32, i1>
    %9 = "neura.phi"(%8, %3) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %10 = neura.reserve : !neura.data<f32, i1>
    %11 = "neura.phi"(%10, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %12 = neura.reserve : !neura.data<f32, i1>
    %13 = "neura.phi"(%12, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %14 = "neura.fcmp"(%13, %9) <{cmpType = "lt"}> : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<i1, i1>
    %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %16 = neura.grant_predicate %11, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %17 = neura.grant_predicate %7, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %18 = neura.grant_predicate %5, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %19 = neura.grant_predicate %9, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %20 = "neura.not"(%14) : (!neura.data<i1, i1>) -> !neura.data<i1, i1>
    %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
    %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
    neura.ctrl_mov %23 -> %12 : !neura.data<f32, i1> !neura.data<f32, i1>
    neura.ctrl_mov %22 -> %10 : !neura.data<f32, i1> !neura.data<f32, i1>
    neura.ctrl_mov %19 -> %8 : !neura.data<f32, i1> !neura.data<f32, i1>
    neura.ctrl_mov %17 -> %6 : !neura.data<f32, i1> !neura.data<f32, i1>
    neura.ctrl_mov %18 -> %4 : !neura.data<f32, i1> !neura.data<f32, i1>
    "neura.return"(%21) : (!neura.data<f32, i1>) -> ()
  }

@ShangkunLi
Copy link
Copy Markdown
Collaborator Author

Thanks @ShangkunLi,

DFG resetting/switching enables iteratively executing a DFG for different loop iterations until we get a valid return value

Why we need this? It sounds different iterations are simultaneously executing, isn't it a mess? Shouldn't it be iter by iter (though this is not dataflow's convention)? In other words, for dataflow, there shouldn't be "iter" concept, we are iterating ready_to_execute_ops based on dependency and is_udpated, right?

Imagine you are executing the DFG in CGRA in a modulo scheduling manner. We need to respect the topological order in a DFG while respecting the recurrence dependence when we want to execute the DFG in the next DFG iteration.

The problem of executing based on the is_updated is that we only focus on the data update and ignore the topological dependence in DFG belonging to different DFG iterations.

For example, for the dataflow ir given in the pr description. The output based on the previous interpreter is

[neura-interpreter]  Initial pending operation: %0 = "neura.grant_once"() <{constant_value = 0.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %1 = "neura.grant_once"() <{constant_value = 1.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %2 = "neura.grant_once"() <{constant_value = 3.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %3 = "neura.grant_once"() <{constant_value = 5.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %4 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %6 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %8 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %10 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %12 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 1 | pending_operation_queue: 9
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %0 = "neura.grant_once"() <{constant_value = 0.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_once:
[neura-interpreter]  ├─ Constant value: 0.000000e+00
[neura-interpreter]  ├─ First access - granting predicate
[neura-interpreter]  └─ Result: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %13 = "neura.phi"(%12, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %11 = "neura.phi"(%10, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %1 = "neura.grant_once"() <{constant_value = 1.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_once:
[neura-interpreter]  ├─ Constant value: 1.000000e+00
[neura-interpreter]  ├─ First access - granting predicate
[neura-interpreter]  └─ Result: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %5 = "neura.phi"(%4, %1) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %2 = "neura.grant_once"() <{constant_value = 3.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_once:
[neura-interpreter]  ├─ Constant value: 3.000000e+00
[neura-interpreter]  ├─ First access - granting predicate
[neura-interpreter]  └─ Result: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %7 = "neura.phi"(%6, %2) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %3 = "neura.grant_once"() <{constant_value = 5.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_once:
[neura-interpreter]  ├─ Constant value: 5.000000e+00
[neura-interpreter]  ├─ First access - granting predicate
[neura-interpreter]  └─ Result: value = 5.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %9 = "neura.phi"(%8, %3) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %4 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Created placeholder  : %4 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Initial value     : 0.0f
[neura-interpreter]     ├─ Initial predicate : false
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %6 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Created placeholder  : %6 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Initial value     : 0.0f
[neura-interpreter]     ├─ Initial predicate : false
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %8 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Created placeholder  : %8 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Initial value     : 0.0f
[neura-interpreter]     ├─ Initial predicate : false
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %10 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Created placeholder  : %10 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Initial value     : 0.0f
[neura-interpreter]     ├─ Initial predicate : false
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %12 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Created placeholder  : %12 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Initial value     : 0.0f
[neura-interpreter]     ├─ Initial predicate : false
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 2 | pending_operation_queue: 5
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %13 = "neura.phi"(%12, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [1] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 0.000000e+00,pred = 0
[neura-interpreter]  │ └─[1]:value = 0.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 0.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %14 = "neura.fcmp"(%13, %9) <{cmpType = "lt"}> : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %11 = "neura.phi"(%10, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [1] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 0.000000e+00,pred = 0
[neura-interpreter]  │ └─[1]:value = 0.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 0.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %16 = neura.grant_predicate %11, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %5 = "neura.phi"(%4, %1) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [1] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 0.000000e+00,pred = 0
[neura-interpreter]  │ └─[1]:value = 1.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 1.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %18 = neura.grant_predicate %5, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %7 = "neura.phi"(%6, %2) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [1] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 0.000000e+00,pred = 0
[neura-interpreter]  │ └─[1]:value = 3.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 3.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %17 = neura.grant_predicate %7, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %9 = "neura.phi"(%8, %3) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [1] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 0.000000e+00,pred = 0
[neura-interpreter]  │ └─[1]:value = 5.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 5.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %19 = neura.grant_predicate %9, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 3 | pending_operation_queue: 7
[neura-interpreter]  Skipping operation (dependencies not satisfied): %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %14 = "neura.fcmp"(%13, %9) <{cmpType = "lt"}> : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  Executing neura.fcmp:
[neura-interpreter]  ├─ Operands 
[neura-interpreter]  │  ├─ LHS               : value = 0.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ RHS               : value = 5.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Evaluation
[neura-interpreter]  │  ├─ Comparison type   : lt
[neura-interpreter]  │  └─ Comparison result : true
[neura-interpreter]  └─ Result               : value = 1.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %20 = "neura.not"(%14) : (!neura.data<i1, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Skipping operation (dependencies not satisfied): %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %16 = neura.grant_predicate %11, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %18 = neura.grant_predicate %5, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %18 -> %4 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %17 = neura.grant_predicate %7, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %17 -> %6 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %19 = neura.grant_predicate %9, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 5.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 5.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %19 -> %8 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 4 | pending_operation_queue: 7
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %20 = "neura.not"(%14) : (!neura.data<i1, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  Executing neura.not:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  └─ Input       : value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Evaluation
[neura-interpreter]  │  └─ Logical NOT : !1
[neura-interpreter]  └─ Result         : value = 0.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.fadd:
[neura-interpreter]  ├─ Operands 
[neura-interpreter]  │  ├─ LHS  : value = 0.000000e+00 [pred = 1]
[neura-interpreter]  │  └─ RHS  : value = 3.000000e+00 [pred = 1]
[neura-interpreter]  └─ Result  : value = 3.000000e+00 [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %22 -> %10 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %18 -> %4 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %18 = neura.grant_predicate %5, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %4 = neura.reserve : !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %18 -> %4 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %5 = "neura.phi"(%4, %1) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.fadd:
[neura-interpreter]  ├─ Operands 
[neura-interpreter]  │  ├─ LHS  : value = 0.000000e+00 [pred = 1]
[neura-interpreter]  │  └─ RHS  : value = 1.000000e+00 [pred = 1]
[neura-interpreter]  └─ Result  : value = 1.000000e+00 [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %23 -> %12 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %17 -> %6 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %17 = neura.grant_predicate %7, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %6 = neura.reserve : !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %17 -> %6 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %7 = "neura.phi"(%6, %2) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %19 -> %8 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %19 = neura.grant_predicate %9, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 5.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %8 = neura.reserve : !neura.data<f32, i1>, value = 5.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %19 -> %8 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %9 = "neura.phi"(%8, %3) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 5 | pending_operation_queue: 9
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Denied access (predicate false)
[neura-interpreter]  └─ Result: value = 0.000000e+00, [pred = 0]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %22 -> %10 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %10 = neura.reserve : !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %22 -> %10 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %11 = "neura.phi"(%10, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %18 -> %4 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %18 = neura.grant_predicate %5, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %4 = neura.reserve : !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 0)
[neura-interpreter]  No update for ctrl_mov target: %4 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %5 = "neura.phi"(%4, %1) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [0] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 1.000000e+00,pred = 1
[neura-interpreter]  │ └─[1]:value = 1.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 1.000000e+00, pred = 1, is_updated = 0
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %23 -> %12 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %12 = neura.reserve : !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %23 -> %12 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %13 = "neura.phi"(%12, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %17 -> %6 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %17 = neura.grant_predicate %7, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %6 = neura.reserve : !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 0)
[neura-interpreter]  No update for ctrl_mov target: %6 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %7 = "neura.phi"(%6, %2) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [0] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 3.000000e+00,pred = 1
[neura-interpreter]  │ └─[1]:value = 3.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 3.000000e+00, pred = 1, is_updated = 0
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %19 -> %8 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %19 = neura.grant_predicate %9, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 5.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %8 = neura.reserve : !neura.data<f32, i1>, value = 5.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 0)
[neura-interpreter]  No update for ctrl_mov target: %8 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %9 = "neura.phi"(%8, %3) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [0] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 5.000000e+00,pred = 1
[neura-interpreter]  │ └─[1]:value = 5.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 5.000000e+00, pred = 1, is_updated = 0
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 6 | pending_operation_queue: 4
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %22 -> %10 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %10 = neura.reserve : !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 0)
[neura-interpreter]  No update for ctrl_mov target: %10 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %11 = "neura.phi"(%10, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [0] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 3.000000e+00,pred = 1
[neura-interpreter]  │ └─[1]:value = 0.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 3.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %16 = neura.grant_predicate %11, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %23 -> %12 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %12 = neura.reserve : !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 0)
[neura-interpreter]  No update for ctrl_mov target: %12 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %13 = "neura.phi"(%12, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [0] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 1.000000e+00,pred = 1
[neura-interpreter]  │ └─[1]:value = 0.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 1.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %14 = "neura.fcmp"(%13, %9) <{cmpType = "lt"}> : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 7 | pending_operation_queue: 4
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Denied access (predicate false)
[neura-interpreter]  └─ Result: value = 3.000000e+00, [pred = 0]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %16 = neura.grant_predicate %11, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %14 = "neura.fcmp"(%13, %9) <{cmpType = "lt"}> : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  Executing neura.fcmp:
[neura-interpreter]  ├─ Operands 
[neura-interpreter]  │  ├─ LHS               : value = 1.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ RHS               : value = 5.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Evaluation
[neura-interpreter]  │  ├─ Comparison type   : lt
[neura-interpreter]  │  └─ Comparison result : true
[neura-interpreter]  └─ Result               : value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ----------------------------------------

In iteration 3, %15 is triggered by %13 update but skipped because %14 is not ready. In iteration 7, %15 is triggered by %13 update again but not skipped because we don't mark the %14 belongs to the last DFG iteration as invalid. So %15 is wrongly executed before %14.

@ShangkunLi
Copy link
Copy Markdown
Collaborator Author

And a general comment:

  • You format re-factoring always put some burden on my review process (i.e., tons of not-related changes/modifications).. Can you not change the format when you implement new things? You can always have a separate PR purely for refactoring before or after your implementation PR, how does it sound~!

It seems that I am using the LLVM format style and you are using the Google format style.

Anyway, I have switched to Google format style. And we can sync to this style by generating the same format configuration file clang-format -style=Google -dump-config > .clang-format

@tancheng
Copy link
Copy Markdown
Contributor

Anyway, I have switched to Google format style. And we can sync to this style by generating the same format configuration file clang-format -style=Google -dump-config > .clang-format

Can this somehow be automated?

@tancheng
Copy link
Copy Markdown
Contributor

Thanks @ShangkunLi,

DFG resetting/switching enables iteratively executing a DFG for different loop iterations until we get a valid return value

Why we need this? It sounds different iterations are simultaneously executing, isn't it a mess? Shouldn't it be iter by iter (though this is not dataflow's convention)? In other words, for dataflow, there shouldn't be "iter" concept, we are iterating ready_to_execute_ops based on dependency and is_udpated, right?

Imagine you are executing the DFG in CGRA in a modulo scheduling manner. We need to respect the topological order in a DFG while respecting the recurrence dependence when we want to execute the DFG in the next DFG iteration.

The problem of executing based on the is_updated is that we only focus on the data update and ignore the topological dependence in DFG belonging to different DFG iterations.

For example, for the dataflow ir given in the pr description. The output based on the previous interpreter is

[neura-interpreter]  Initial pending operation: %0 = "neura.grant_once"() <{constant_value = 0.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %1 = "neura.grant_once"() <{constant_value = 1.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %2 = "neura.grant_once"() <{constant_value = 3.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %3 = "neura.grant_once"() <{constant_value = 5.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %4 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %6 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %8 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %10 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Initial pending operation: %12 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 1 | pending_operation_queue: 9
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %0 = "neura.grant_once"() <{constant_value = 0.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_once:
[neura-interpreter]  ├─ Constant value: 0.000000e+00
[neura-interpreter]  ├─ First access - granting predicate
[neura-interpreter]  └─ Result: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %13 = "neura.phi"(%12, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %11 = "neura.phi"(%10, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %1 = "neura.grant_once"() <{constant_value = 1.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_once:
[neura-interpreter]  ├─ Constant value: 1.000000e+00
[neura-interpreter]  ├─ First access - granting predicate
[neura-interpreter]  └─ Result: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %5 = "neura.phi"(%4, %1) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %2 = "neura.grant_once"() <{constant_value = 3.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_once:
[neura-interpreter]  ├─ Constant value: 3.000000e+00
[neura-interpreter]  ├─ First access - granting predicate
[neura-interpreter]  └─ Result: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %7 = "neura.phi"(%6, %2) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %3 = "neura.grant_once"() <{constant_value = 5.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_once:
[neura-interpreter]  ├─ Constant value: 5.000000e+00
[neura-interpreter]  ├─ First access - granting predicate
[neura-interpreter]  └─ Result: value = 5.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %9 = "neura.phi"(%8, %3) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %4 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Created placeholder  : %4 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Initial value     : 0.0f
[neura-interpreter]     ├─ Initial predicate : false
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %6 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Created placeholder  : %6 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Initial value     : 0.0f
[neura-interpreter]     ├─ Initial predicate : false
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %8 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Created placeholder  : %8 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Initial value     : 0.0f
[neura-interpreter]     ├─ Initial predicate : false
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %10 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Created placeholder  : %10 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Initial value     : 0.0f
[neura-interpreter]     ├─ Initial predicate : false
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %12 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Created placeholder  : %12 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Initial value     : 0.0f
[neura-interpreter]     ├─ Initial predicate : false
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 2 | pending_operation_queue: 5
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %13 = "neura.phi"(%12, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [1] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 0.000000e+00,pred = 0
[neura-interpreter]  │ └─[1]:value = 0.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 0.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %14 = "neura.fcmp"(%13, %9) <{cmpType = "lt"}> : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %11 = "neura.phi"(%10, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [1] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 0.000000e+00,pred = 0
[neura-interpreter]  │ └─[1]:value = 0.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 0.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %16 = neura.grant_predicate %11, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %5 = "neura.phi"(%4, %1) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [1] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 0.000000e+00,pred = 0
[neura-interpreter]  │ └─[1]:value = 1.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 1.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %18 = neura.grant_predicate %5, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %7 = "neura.phi"(%6, %2) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [1] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 0.000000e+00,pred = 0
[neura-interpreter]  │ └─[1]:value = 3.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 3.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %17 = neura.grant_predicate %7, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %9 = "neura.phi"(%8, %3) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [1] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 0.000000e+00,pred = 0
[neura-interpreter]  │ └─[1]:value = 5.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 5.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %19 = neura.grant_predicate %9, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 3 | pending_operation_queue: 7
[neura-interpreter]  Skipping operation (dependencies not satisfied): %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %14 = "neura.fcmp"(%13, %9) <{cmpType = "lt"}> : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  Executing neura.fcmp:
[neura-interpreter]  ├─ Operands 
[neura-interpreter]  │  ├─ LHS               : value = 0.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ RHS               : value = 5.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Evaluation
[neura-interpreter]  │  ├─ Comparison type   : lt
[neura-interpreter]  │  └─ Comparison result : true
[neura-interpreter]  └─ Result               : value = 1.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %20 = "neura.not"(%14) : (!neura.data<i1, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Skipping operation (dependencies not satisfied): %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %16 = neura.grant_predicate %11, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %18 = neura.grant_predicate %5, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %18 -> %4 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %17 = neura.grant_predicate %7, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %17 -> %6 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %19 = neura.grant_predicate %9, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 5.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 5.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %19 -> %8 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 4 | pending_operation_queue: 7
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %20 = "neura.not"(%14) : (!neura.data<i1, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  Executing neura.not:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  └─ Input       : value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Evaluation
[neura-interpreter]  │  └─ Logical NOT : !1
[neura-interpreter]  └─ Result         : value = 0.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.fadd:
[neura-interpreter]  ├─ Operands 
[neura-interpreter]  │  ├─ LHS  : value = 0.000000e+00 [pred = 1]
[neura-interpreter]  │  └─ RHS  : value = 3.000000e+00 [pred = 1]
[neura-interpreter]  └─ Result  : value = 3.000000e+00 [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %22 -> %10 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %18 -> %4 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %18 = neura.grant_predicate %5, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %4 = neura.reserve : !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %18 -> %4 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %5 = "neura.phi"(%4, %1) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.fadd:
[neura-interpreter]  ├─ Operands 
[neura-interpreter]  │  ├─ LHS  : value = 0.000000e+00 [pred = 1]
[neura-interpreter]  │  └─ RHS  : value = 1.000000e+00 [pred = 1]
[neura-interpreter]  └─ Result  : value = 1.000000e+00 [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %23 -> %12 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %17 -> %6 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %17 = neura.grant_predicate %7, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %6 = neura.reserve : !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %17 -> %6 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %7 = "neura.phi"(%6, %2) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %19 -> %8 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %19 = neura.grant_predicate %9, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 5.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %8 = neura.reserve : !neura.data<f32, i1>, value = 5.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %19 -> %8 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %9 = "neura.phi"(%8, %3) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 5 | pending_operation_queue: 9
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Denied access (predicate false)
[neura-interpreter]  └─ Result: value = 0.000000e+00, [pred = 0]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %22 -> %10 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %10 = neura.reserve : !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %22 -> %10 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %11 = "neura.phi"(%10, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %18 -> %4 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %18 = neura.grant_predicate %5, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %4 = neura.reserve : !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 0)
[neura-interpreter]  No update for ctrl_mov target: %4 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %5 = "neura.phi"(%4, %1) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [0] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 1.000000e+00,pred = 1
[neura-interpreter]  │ └─[1]:value = 1.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 1.000000e+00, pred = 1, is_updated = 0
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %23 -> %12 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %12 = neura.reserve : !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: neura.ctrl_mov %23 -> %12 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %13 = "neura.phi"(%12, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %17 -> %6 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %17 = neura.grant_predicate %7, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %6 = neura.reserve : !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 0)
[neura-interpreter]  No update for ctrl_mov target: %6 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %7 = "neura.phi"(%6, %2) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [0] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 3.000000e+00,pred = 1
[neura-interpreter]  │ └─[1]:value = 3.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 3.000000e+00, pred = 1, is_updated = 0
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %19 -> %8 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %19 = neura.grant_predicate %9, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>, value = 5.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %8 = neura.reserve : !neura.data<f32, i1>, value = 5.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 0)
[neura-interpreter]  No update for ctrl_mov target: %8 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %9 = "neura.phi"(%8, %3) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [0] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 5.000000e+00,pred = 1
[neura-interpreter]  │ └─[1]:value = 5.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 5.000000e+00, pred = 1, is_updated = 0
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 6 | pending_operation_queue: 4
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %22 -> %10 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %10 = neura.reserve : !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 0)
[neura-interpreter]  No update for ctrl_mov target: %10 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %11 = "neura.phi"(%10, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [0] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 3.000000e+00,pred = 1
[neura-interpreter]  │ └─[1]:value = 0.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 3.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %16 = neura.grant_predicate %11, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %23 -> %12 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %12 = neura.reserve : !neura.data<f32, i1>, value = 1.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 0)
[neura-interpreter]  No update for ctrl_mov target: %12 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %13 = "neura.phi"(%12, %0) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.phi(dataflow):
[neura-interpreter]  ├─ Selected input [0] (latest valid)
[neura-interpreter]  ├─ Input values (2)
[neura-interpreter]  │ ├─[0]:value = 1.000000e+00,pred = 1
[neura-interpreter]  │ └─[1]:value = 0.000000e+00,pred = 1
[neura-interpreter]  └─ Execution succeeded | Result: value = 1.000000e+00, pred = 1, is_updated = 1
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Added user to next pending_operation_queue: %14 = "neura.fcmp"(%13, %9) <{cmpType = "lt"}> : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 7 | pending_operation_queue: 4
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %21 = neura.grant_predicate %11, %20 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 0.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Denied access (predicate false)
[neura-interpreter]  └─ Result: value = 3.000000e+00, [pred = 0]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %16 = neura.grant_predicate %11, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 3.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %15 = neura.grant_predicate %13, %14 : !neura.data<f32, i1>, !neura.data<i1, i1> -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_predicate:
[neura-interpreter]  ├─ Operand
[neura-interpreter]  │  ├─ Source: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ New predicate: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Granted access
[neura-interpreter]  └─ Result: value = 1.000000e+00, [pred = 1]
[neura-interpreter]  Operation updated, propagating to users...
[neura-interpreter]  Added user to next pending_operation_queue: %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %14 = "neura.fcmp"(%13, %9) <{cmpType = "lt"}> : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<i1, i1>
[neura-interpreter]  Executing neura.fcmp:
[neura-interpreter]  ├─ Operands 
[neura-interpreter]  │  ├─ LHS               : value = 1.000000e+00, [pred = 1]
[neura-interpreter]  │  └─ RHS               : value = 5.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Evaluation
[neura-interpreter]  │  ├─ Comparison type   : lt
[neura-interpreter]  │  └─ Comparison result : true
[neura-interpreter]  └─ Result               : value = 1.000000e+00, [pred = 1]
[neura-interpreter]  ----------------------------------------

In iteration 3, %15 is triggered by %13 update but skipped because %14 is not ready. In iteration 7, %15 is triggered by %13 update again but not skipped because we don't mark the %14 belongs to the last DFG iteration as invalid. So %15 is wrongly executed before %14.

Can you help me understand why we need "iteration" here? Why can't we just keep a pending_execute_ops_queue to fire op's execution one by one?

@ShangkunLi
Copy link
Copy Markdown
Collaborator Author

Anyway, I have switched to Google format style. And we can sync to this style by generating the same format configuration file clang-format -style=Google -dump-config > .clang-format

Can this somehow be automated?

We can add some actions to automatically generate formatted code after merging.

@itemkelvin
Copy link
Copy Markdown
Collaborator

itemkelvin commented Aug 25, 2025 via email

@tancheng
Copy link
Copy Markdown
Contributor

@itemkelvin @ShangkunLi Don't you think my suggestion is cleaner? Or any potential issue we can't maintain a queue w/o a buffer?

@tancheng
Copy link
Copy Markdown
Contributor

Anyway, I have switched to Google format style. And we can sync to this style by generating the same format configuration file clang-format -style=Google -dump-config > .clang-format

Can this somehow be automated?

We can add some actions to automatically generate formatted code after merging.

That Github action won't be a part of PR, let's just manually tune it. What command I need to use on my side to cleanup the format?

@itemkelvin
Copy link
Copy Markdown
Collaborator

itemkelvin commented Aug 25, 2025 via email

@tancheng
Copy link
Copy Markdown
Contributor

Actually, the instructions are still executed in the order of a queue. It's just that during the implementation, I wanted to check whether each instruction could propagate, which led to the vector being retained. It's feasible to change it to a queue.

------------------ Original ------------------ From: Cheng Tan @.> Date: Mon,Aug 25,2025 2:32 PM To: coredac/dataflow @.> Cc: item @.>, Mention @.> Subject: Re: [coredac/dataflow] Refactor the dataflow mode logic (PR #121) tancheng left a comment (coredac/dataflow#121) @itemkelvin @ShangkunLi Don't you think my suggestion is cleaner? Or any potential issue we can't maintain a queue w/o a buffer? — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

Cool, let's do it in the next cleanup PR.

@ShangkunLi
Copy link
Copy Markdown
Collaborator Author

@itemkelvin @ShangkunLi Don't you think my suggestion is cleaner? Or any potential issue we can't maintain a queue w/o a buffer?

I think current implementation meets your requirements. I just maintain a ready_to_execute_ops for

Actually, the instructions are still executed in the order of a queue. It's just that during the implementation, I wanted to check whether each instruction could propagate, which led to the vector being retained. It's feasible to change it to a queue.

------------------ Original ------------------ From: Cheng Tan @.> Date: Mon,Aug 25,2025 2:32 PM To: coredac/dataflow @.> Cc: item @.>, Mention @.> Subject: Re: [coredac/dataflow] Refactor the dataflow mode logic (PR #121) tancheng left a comment (coredac/dataflow#121) @itemkelvin @ShangkunLi Don't you think my suggestion is cleaner? Or any potential issue we can't maintain a queue w/o a buffer? — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

Thanks~! It would be better if we could keep the original implementation.

Then we can deprecate this pr, right? @tancheng

@tancheng
Copy link
Copy Markdown
Contributor

@ShangkunLi,

I think current implementation meets your requirements. I just maintain a ready_to_execute_ops for

But your dump msg still shows iter 1, iter 2, iter 3. This PR LGTM anyways, let's make cleanup later.

@ShangkunLi
Copy link
Copy Markdown
Collaborator Author

@ShangkunLi,

I think current implementation meets your requirements. I just maintain a ready_to_execute_ops for

But your dump msg still shows iter 1, iter 2, iter 3. This PR LGTM anyways, let's make cleanup later.

Current dump msg looks like

[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 18 | ready_to_execute_ops: 3
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: "neura.return"(%21) : (!neura.data<f32, i1>) -> ()
[neura-interpreter]  Executing neura.return:
[neura-interpreter]  ├─ Return values:
[neura-interpreter]  │  └─0.000000, [pred = 0]
[neura-interpreter]  └─ Execution terminated successfully
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %22 -> %10 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %22 = "neura.fadd"(%16, %17) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>, value = 9.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %10 = neura.reserve : !neura.data<f32, i1>, value = 9.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  CtrlMov target updated: %10 = neura.reserve : !neura.data<f32, i1>, value = 9.000000e+00, [pred = 1]
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: neura.ctrl_mov %23 -> %12 : !neura.data<f32, i1> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.ctrl_mov(dataflow):
[neura-interpreter]  ├─ Source: %23 = "neura.fadd"(%15, %18) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  ├─ Target: %12 = neura.reserve : !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  └─ Updated (is_updated = 1)
[neura-interpreter]  CtrlMov target updated: %12 = neura.reserve : !neura.data<f32, i1>, value = 3.000000e+00, [pred = 1]
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  DFG boundary crossing 3
[neura-interpreter]  New ready to execute operations after DFG reset:
[neura-interpreter]  │  %6 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  │  %8 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  │  %3 = "neura.grant_once"() <{constant_value = 5.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  │  %0 = "neura.grant_once"() <{constant_value = 0.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  │  %4 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  │  %2 = "neura.grant_once"() <{constant_value = 3.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  │  %1 = "neura.grant_once"() <{constant_value = 1.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  │  %10 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  │  %12 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  ----------------------------------------
[neura-interpreter]  Iteration 19 | ready_to_execute_ops: 9
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %6 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Preserving existing placeholder: %6 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Current value     : 3.000000e+00
[neura-interpreter]     ├─ Current predicate : 1
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %8 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Preserving existing placeholder: %8 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Current value     : 5.000000e+00
[neura-interpreter]     ├─ Current predicate : 1
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %3 = "neura.grant_once"() <{constant_value = 5.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_once:
[neura-interpreter]  ├─ Constant value: 5.000000e+00
[neura-interpreter]  ├─ Subsequent access - denying predicate
[neura-interpreter]  └─ Result: value = 5.000000e+00, [pred = 0]
[neura-interpreter]  Added dependent consumer op to next_ready_to_execute_ops: %9 = "neura.phi"(%8, %3) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %0 = "neura.grant_once"() <{constant_value = 0.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_once:
[neura-interpreter]  ├─ Constant value: 0.000000e+00
[neura-interpreter]  ├─ Subsequent access - denying predicate
[neura-interpreter]  └─ Result: value = 0.000000e+00, [pred = 0]
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %4 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]  Executing neura.reserve:
[neura-interpreter]  └─ Preserving existing placeholder: %4 = neura.reserve : !neura.data<f32, i1>
[neura-interpreter]     ├─ Current value     : 1.000000e+00
[neura-interpreter]     ├─ Current predicate : 1
[neura-interpreter]     └─ Type              : !neura.data<f32, i1>
[neura-interpreter]  ========================================
[neura-interpreter]  Executing operation: %2 = "neura.grant_once"() <{constant_value = 3.000000e+00 : f32}> : () -> !neura.data<f32, i1>
[neura-interpreter]  Executing neura.grant_once:
[neura-interpreter]  ├─ Constant value: 3.000000e+00
[neura-interpreter]  ├─ Subsequent access - denying predicate
[neura-interpreter]  └─ Result: value = 3.000000e+00, [pred = 0]
[neura-interpreter]  Added dependent consumer op to next_ready_to_execute_ops: %7 = "neura.phi"(%6, %2) : (!neura.data<f32, i1>, !neura.data<f32, i1>) -> !neura.data<f32, i1>

Here, each iteration means the level of topological order we are in. And DFG crossing means we have executed all the operations in the DFG, and we need to execute the next iteration of DFG. And the ready operations are grant_once and reserve, but only reserve ops have valid predicate bit.

@ShangkunLi
Copy link
Copy Markdown
Collaborator Author

Anyway, I have switched to Google format style. And we can sync to this style by generating the same format configuration file clang-format -style=Google -dump-config > .clang-format

Can this somehow be automated?

We can add some actions to automatically generate formatted code after merging.

That Github action won't be a part of PR, let's just manually tune it. What command I need to use on my side to cleanup the format?

You can install clangd extension in vscode. And use apt install clang-format in your server. And generate the configuration file use clang-format -style=Google -dump-config > .clang-format and put .clang-format in your workspace (e.g., dataflow). Then you can format your C/C++ code based on the configuration file.

@ShangkunLi ShangkunLi merged commit b9ffc09 into coredac:main Aug 25, 2025
1 check passed
ShangkunLi added a commit that referenced this pull request Mar 12, 2026
Refactor the dataflow mode logic interpreter
ShangkunLi added a commit that referenced this pull request Mar 12, 2026
Refactor the dataflow mode logic interpreter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P0] Github verification fails after checking in https://github.com/coredac/dataflow/pull/105

3 participants