Skip to content

Recursive let-expressions throw DEC transformation into a loop #1316

Description

@christiaanb

The following reduced test-case:

import Clash.Prelude

incr :: Index 2 -> Index 2
incr i = if i == maxBound then 0 else i + 1
{-# NOINLINE incr #-}

topEntity :: Index 10 -> Index 2
topEntity j = case j < 1 of
  False ->
    let xs = init (Cons 1 (Cons (incr (head xs)) Nil)) in last xs
  True ->
    let ys = init (Cons 2 (Cons (incr (last ys)) Nil)) in head ys

throws the DEC transformation into a loop. Specifically, DEC rewrites:

case j < 1 of
  False ->
    let xs = init (Cons 1 (Cons (incr (head xs)) Nil)) in last xs
  True ->
    let ys = init (Cons 2 (Cons (incr (last ys)) Nil)) in head ys

to

let incrOut = incr (case j < 1 of
  False ->
    let xs = init (Cons 1 (Cons (incr (head xs)) Nil)) in head xs
  True ->
    let ys = init (Cons 2 (Cons (incr (last ys)) Nil)) in last ys)
in case j < 1 of
  False ->
    let xs = init (Cons 1 (Cons incrOut Nil)) in last xs
  True ->
    let ys = init (Cons 2 (Cons incrOut Nil)) in head ys

trying to share uses of incr between the two case-alternatives; only to create a new case-expression on which DEC can match again. What DEC should be doing is rewrite to:

let incrOut = incr (case j < 1 of
  False ->
    let xs = init (Cons 1 (Cons incrOut Nil)) in head xs
  True ->
    let ys = init (Cons 2 (Cons incrOut Nil)) in last ys)
in case j < 1 of
  False ->
    let xs = init (Cons 1 (Cons incrOut Nil)) in last xs
  True ->
    let ys = init (Cons 2 (Cons incrOut Nil)) in head ys

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions