Replies: 2 comments 2 replies
-
Nice write-up @doug-q :). We might wish to note there are several distinct reasons why nodes might be "never-dce" - it's probably OK to combine these but there might be reasons to distinguish
While the "linear state token" allows rewriting in the opposite impure->pure direction, even there one wants to do a lot more tidying up. Side comment, but I'd like to unify treatment of "never-dce" ops/nodes with unbounded TailLoops somehow. |
Beta Was this translation helpful? Give feedback.
-
Isn't a major design point of HUGR that it uses "value semantics", i.e. data dependencies are all there is? The "never-dce" and order edge approaches feel like hacks in that light while the "linear state token" expresses precisely what we want, both conceptually and pragmatically. It makes control dependencies into data dependencies where we want it, and so requires no additional attention to corner cases regarding ordering or effects. It marks effectfulness directly in the type of an operation. It is immediately clear how it interacts with control flow. This is also a solution that some people in PL semantics research have arrived at (see e.g. Universal Properties of Impure Programming Languages or Promonads and String Diagrams for Effectful Categories).
These should definitely be dead.
Can you explain what you mean here? |
Beta Was this translation helpful? Give feedback.
-
Dead code elimination is a well known concept in compilers. https://en.wikipedia.org/wiki/Dead-code_elimination
See #1807 for issues with our existing dead-code-elimination, which at time of writing lives in and around
ConstFoldPass::find_needed_nodes
.By dead, we mean "it's outputs aren't used". This is similar but different to "unreachable" which means "no dynamic trace of the program executes that basic block". It's always safe to remove unreachable basic blocks.
Our dead code elimination must eliminate "dead" ops, for which we need a definition of "dead". Some examples of ops that are surely dead:
int.iadd
whose outputs are not usedSome ops that are surely not dead:
int.add
whose outputs are wired to the Output node of a public FuncDefnint.iadd
whose outputs are wired to the Output node of that DFGAre the following ops dead?
Does the addition of order edges between the input and output nodes and the panic nodes affect the above?
Focusing now on the panic case, I assume that we want all panics in a live DFG to be live, irrespective of their connections.
Options:
Put a "never-dce" flag on
OpDef
. (maybe inmisc
?).Ops connected (perhaps through order edges) to the output node of their parent dataflow block are never dead unless their parent is.
Create a linear "state token" and thread it through all impure ops
My view is we should move forward with a "never-dce" flag.
Beta Was this translation helpful? Give feedback.
All reactions