mergeBounds :: forall m . (MonadInterp m Range) => Traversal AST m
mergeBounds ExpA (ForE ParFor loopvs p) = do
    (ds, es')  <- unzip <$> mapM simplBound loopvs
    extendVars (vs `zip` ds) $ do
    ForE ParFor (vs `zip` es') <$> (fromMnf <$> go (toMnf p))
  where
    vs = map fst loopvs

    simplBound :: (Var, Exp) -> m (Range, Exp)
    simplBound (_, e) = do
        e' <- mergeBounds ExpA e
        d  <- rangeE e'
        case d of
          Range i -> return (d, iToExp i)
          T       -> return (d, e')

    go :: Mnf Exp -> m (Mnf Exp)
    go [] =
        return []

    go ((seq1, IfThenElseE e1 p1a p1b):(seq2, IfThenElseE e2 p2a p2b):ms)
      | e1 ==! e2 && not (isLetM seq1) && not (isLetM seq2) =
        go ((seq2, IfThenElseE e1 (p1a `seq'` p2a) (p1b `seq'` p2b)):ms)
      where
        seq' = case seq1 of
                 ParM -> parE
                 _    -> seqE

    go ((seq1, IfThenElseE e1 p1a p1b):(_, SyncE):(seq3, IfThenElseE e2 p2a p2b):ms)
      | e1 ==! e2 && not (isLetM seq1) && not (isLetM seq3) =
        go ((seq3, IfThenElseE e1 (p1a `syncE` p2a) (p1b `syncE` p2b)):ms)

    go ((seq1, m@(IfThenElseE (BinopE LtO (VarE v) e) p1 _)):ms)
      | not (isLetM seq1) = do
        d1 <- lookupVar v
        d2 <- Just <$> rangeE e
        if d1 == d2
          then go ((seq1,p1):ms)
          else do  m'  <- mergeBounds ExpA m
                   ms' <- go ms
                   return $ (seq1,m') : ms'

    go ((seq1,m) : ms) = do
        m'  <- mergeBounds ExpA m
        ms' <- go ms
        return $ (seq1,m') : ms'

    isLetM :: SeqM -> Bool
    isLetM (LetM {}) = True
    isLetM _         = False
mergeBounds :: forall m . (MonadInterp m Range) => Traversal AST m
mergeBounds ExpA (ForE ParFor loopvs p) = do
    (ds, es')  <- unzip <$> mapM simplBound loopvs
    extendVars (vs `zip` ds) $ do
    ForE ParFor (vs `zip` es') <$> (fromMnf <$> go (toMnf p))
  where
    vs = map fst loopvs

    simplBound :: (Var, Exp) -> m (Range, Exp)
    simplBound (_, e) = do
        e' <- mergeBounds ExpA e
        d  <- rangeE e'
        case d of
          Range i -> return (d, iToExp i)
          T       -> return (d, e')

    go :: Mnf Exp -> m (Mnf Exp)
    go [] =
        return []

    go ((seq1, IfThenElseE e1 p1a p1b):(seq2, IfThenElseE e2 p2a p2b):ms)
      | e1 ==! e2 && not (isLetM seq1) && not (isLetM seq2) =
        go ((seq2, IfThenElseE e1 (p1a `seq'` p2a) (p1b `seq'` p2b)):ms)
      where
        seq' = case seq1 of
                 ParM -> parE
                 _    -> seqE

    go ((seq1, IfThenElseE e1 p1a p1b):(_, SyncE):(seq3, IfThenElseE e2 p2a p2b):ms)
      | e1 ==! e2 && not (isLetM seq1) && not (isLetM seq3) =
        go ((seq3, IfThenElseE e1 (p1a `syncE` p2a) (p1b `syncE` p2b)):ms)

    go ((seq1, m@(IfThenElseE (BinopE LtO (VarE v) e) p1 _)):ms)
      | not (isLetM seq1) = do
        d1 <- lookupVar v
        d2 <- Just <$> rangeE e
        if d1 == d2
          then go ((seq1,p1):ms)
          else do  m'  <- mergeBounds ExpA m
                   ms' <- go ms
                   return $ (seq1,m') : ms'

    go ((seq1,m) : ms) = do
        m'  <- mergeBounds ExpA m
        ms' <- go ms
        return $ (seq1,m') : ms'

    isLetM :: SeqM -> Bool
    isLetM (LetM {}) = True
    isLetM _         = False
mergeBounds ExpA (ForE ParFor loopvs p) = do
    (ds, es')  <- unzip <$> mapM simplBound loopvs
    extendVars (vs `zip` ds) $ do
    ForE ParFor (vs `zip` es') <$> (fromMnf <$> go (toMnf p))
  where
    vs = map fst loopvs

    simplBound :: (Var, Exp) -> m (Range, Exp)
    simplBound (_, e) = do
        e' <- mergeBounds ExpA e
        d  <- rangeE e'
        case d of
          Range i -> return (d, iToExp i)
          T       -> return (d, e')

    go :: Mnf Exp -> m (Mnf Exp)
    go [] =
        return []

    go ((seq1, IfThenElseE e1 p1a p1b):(seq2, IfThenElseE e2 p2a p2b):ms)
      | e1 ==! e2 && not (isLetM seq1) && not (isLetM seq2) =
        go ((seq2, IfThenElseE e1 (p1a `seq'` p2a) (p1b `seq'` p2b)):ms)
      where
        seq' = case seq1 of
                 ParM -> parE
                 _    -> seqE

    go ((seq1, IfThenElseE e1 p1a p1b):(_, SyncE):(seq3, IfThenElseE e2 p2a p2b):ms)
      | e1 ==! e2 && not (isLetM seq1) && not (isLetM seq3) =
        go ((seq3, IfThenElseE e1 (p1a `syncE` p2a) (p1b `syncE` p2b)):ms)

    go ((seq1, m@(IfThenElseE (BinopE LtO (VarE v) e) p1 _)):ms)
      | not (isLetM seq1) = do
        d1 <- lookupVar v
        d2 <- Just <$> rangeE e
        if d1 == d2
          then go ((seq1,p1):ms)
          else do  m'  <- mergeBounds ExpA m
                   ms' <- go ms
                   return $ (seq1,m') : ms'

    go ((seq1,m) : ms) = do
        m'  <- mergeBounds ExpA m
        ms' <- go ms
        return $ (seq1,m') : ms'

    isLetM :: SeqM -> Bool
    isLetM (LetM {}) = True
    isLetM _         = False