I’ve been working on a large refactor, which should help resolve some fundamental problems with the IR.
Currently, all steps are stored as Rcs. When a step is used in multiple places in the IR, it is deeply cloned (i.e. the underlying Step is cloned and assigned a new ID, rather than just cloning the Rc). This causes problems where a step needs mutating, but it’s been cloned: some versions lag behind and are never updated. For instance, when we encounter a loop in which the last block yields, or doesn’t continue the opcode stack linearly (think: non-warped proc calls, broadcast and wait), the loop isnt properly constructed and we end up terminating after only one iteration.
To fix this, I’m trying to give steps types that reflect their use. Non-inlined steps (those that are started at the top-level by the scheduler) are stored as RefCells in a central map, and referenced elsewhere by a StepIndex (a wrapper around usize). Inlined steps - e.g. if/else statement bodies - are stored everywhere as Rc<RefCell>s and not stored centrally. When inlined steps are used in multiple places, they are cloned lazily, i.e. only when they need context-aware mutation.
I have done most of this and am now left with another small problem, to do with newly introduced polymorphisms over the two kinds of steps. In such contexts, when I want to reason about all steps - e.g. in the SSA pass, where each step is associated with a graph - it’s not clear how steps should be stored. To sort this out I’ll probably create some sort of Step trait implemented for the relevant types, backed by the current Step struct, with some sort of dynamic dispatch for hashing. Or, I might change some algorithms to avoid needing such a collection of steps - I have yet to decide. Regardless, now seemed like a good place to make a commit before I make yet more big changes.
Today’s image is the latest commit summary (I’ve nothing else to give as it doesn’t compile yet)