Barrier insertion: Rework barrier insertion to keep finer track of
dependencies, and also to treat loops more carefully. * Dependencies are now tracked based on a list of active potential sources, and the active set is narrowed by filtering through readers/writers * Stricter handling of dependencies within loops by not assuming that loops are nonempty * Changes the barrier insertion algorithm to act in two stages: first, barriers are recursively inserted into loops, then they are inserted at the outermost level. This is mostly meant to simplify the code. * See also #18 on gitlab