Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data.Vector.Generic.length not fusible #306

Closed
gksato opened this issue Jun 3, 2020 · 0 comments · Fixed by #307
Closed

Data.Vector.Generic.length not fusible #306

gksato opened this issue Jun 3, 2020 · 0 comments · Fixed by #307
Milestone

Comments

@gksato
Copy link
Contributor

gksato commented Jun 3, 2020

Unfortunately, the function Data.Vector.Generic.length is not currently covered by stream fusion. This is because length is defined in terms of Data.Vector.Generic.stream', which does not admit fusion rules at all.

As a result, the following simple code:
https://gist.github.com/gksato/417030a1f19f1f376dcb2fabaf66c10a#file-test-hs
does require a big allocation:
https://gist.github.com/gksato/417030a1f19f1f376dcb2fabaf66c10a#file-testbefore-ddump-simpl

I'm soon gonna submit a pull request to fix this!

gksato added a commit to gksato/vector that referenced this issue Jun 3, 2020
This change makes fusible 'Data.Vector.Generic.length',
which currently can be inlined but doesn't fuse well.
Before this revision, 'length' uses non-fusible 'stream''.
This revision replaces 'stream'' with fusible 'stream',
and at the same time substitute the mutually-recursive
occurrences of 'length' with 'basicLength'.

Rationale:
The current definition was introduced in the commit
a811a86.
Prior to that commit, 'length' could not even be inlined,
because GHC elected it to be a loop-breaker due to
the cyclic references among 'stream', 'clone', 'length', and
'unsafeCopy'.
This failure of inlining was reported as
haskell#97.

The commit a811a86 resolved this by replacing 'stream'
with 'stream'' in the definition of 'length'. The function
'stream' refers to 'clone' in its fusion rule, but 'stream''
doesn't possess any rule. This cuts open the cycle of references
and makes 'length' inlinable.

However, since 'stream'' doesn't possess any rule, defining
'length' = 'Bundle.length' . 'stream''
is all the same as setting
'length' = 'basicLength'.
This prevents any stream fusion from
happening.

This commit resolves this problem by resetting 'length' back
to be 'Bundle.length' . 'stream', and instead replacing
cyclic occurrence of 'length' with 'basicLength'
(Just *inlined the simplification result of the definition*).
Now 'length' is both inlinable and fusible.

Fixes: haskell#306
See also: haskell#97
@Shimuuar Shimuuar added this to the 0.13 milestone Jun 11, 2020
gksato added a commit to gksato/vector that referenced this issue Jun 20, 2020
This change makes fusible 'Data.Vector.Generic.length',
which currently can be inlined but doesn't fuse well.
Before this revision, 'length' uses non-fusible 'stream''.
This revision replaces 'stream'' with fusible 'stream',
and at the same time substitute the mutually-recursive
occurrences of 'length' with 'basicLength'.

Rationale:
The current definition was introduced in the commit
a811a86.
Prior to that commit,
'length' could not even be inlined with older GHCs,
which elected 'length' to be a loop-breaker due to the cyclic
references among 'clone', 'unsafeCopy', 'length' and 'stream':
* 'clone' refers to 'length' and 'unsafeCopy' in its definition;
* 'unsafeCopy' refers to 'length' in its definition;
* 'length' referred to 'stream' in its definition;
* 'stream' refers to none of the above in its definition,
  but the rule 'New.unstream/stream' rewrites
  @'New.unstream' ('stream' v)@ with @'clone' v@.
This failure of inlining was reported as
haskell#97.

To be precise, this cycle of references is immaterial with newer
GHCs like GHC 8.8.3.
Since 'New.unstream' does not occur in the definitions of
'clone', 'unsafeCopy', and 'length',
indefinite inlining will not happen anyway.
GHC 8.8.3 seems to detect this immateriality of the
referencial loop in question and refrains from setting 'length' as a
loop-breaker, even with
acdcff3
(the parent commit of a811a86).
However with older GHCs, including GHC 8.0.2, regarded
the cyclic references fatal and marked 'length' as a loop-breaker.
Note that GHC 8.0.2 was current at the time a811a86 was introduced.

The commit a811a86 resolved this by replacing 'stream'
with 'stream'' in the definition of 'length'. The function
'stream' refers to 'clone' in its fusion rule, but 'stream''
doesn't possess any rule. This cut open the cycle of references
and made 'length' inlinable.

However, since 'stream'' doesn't possess any rule, defining
'length' = 'Bundle.length' . 'stream''
is all the same as setting
'length' = 'basicLength'.
This prevents any stream fusion from happening.

This commit resolves this problem by resetting 'length' back
to be @'Bundle.length' . 'stream'@, and instead replacing
cyclic occurrence of 'length' with 'basicLength'
(Just *inlined the simplification result of the definition*).
Now 'length' is both inlinable and fusible, even with older GHCs.

Fixes: haskell#306
See also: haskell#97
  haskell#111
  haskell#155
Shimuuar pushed a commit that referenced this issue Jun 21, 2020
This change makes fusible 'Data.Vector.Generic.length',
which currently can be inlined but doesn't fuse well.
Before this revision, 'length' uses non-fusible 'stream''.
This revision replaces 'stream'' with fusible 'stream',
and at the same time substitute the mutually-recursive
occurrences of 'length' with 'basicLength'.

Rationale:
The current definition was introduced in the commit
a811a86.
Prior to that commit,
'length' could not even be inlined with older GHCs,
which elected 'length' to be a loop-breaker due to the cyclic
references among 'clone', 'unsafeCopy', 'length' and 'stream':
* 'clone' refers to 'length' and 'unsafeCopy' in its definition;
* 'unsafeCopy' refers to 'length' in its definition;
* 'length' referred to 'stream' in its definition;
* 'stream' refers to none of the above in its definition,
  but the rule 'New.unstream/stream' rewrites
  @'New.unstream' ('stream' v)@ with @'clone' v@.
This failure of inlining was reported as
#97.

To be precise, this cycle of references is immaterial with newer
GHCs like GHC 8.8.3.
Since 'New.unstream' does not occur in the definitions of
'clone', 'unsafeCopy', and 'length',
indefinite inlining will not happen anyway.
GHC 8.8.3 seems to detect this immateriality of the
referencial loop in question and refrains from setting 'length' as a
loop-breaker, even with
acdcff3
(the parent commit of a811a86).
However with older GHCs, including GHC 8.0.2, regarded
the cyclic references fatal and marked 'length' as a loop-breaker.
Note that GHC 8.0.2 was current at the time a811a86 was introduced.

The commit a811a86 resolved this by replacing 'stream'
with 'stream'' in the definition of 'length'. The function
'stream' refers to 'clone' in its fusion rule, but 'stream''
doesn't possess any rule. This cut open the cycle of references
and made 'length' inlinable.

However, since 'stream'' doesn't possess any rule, defining
'length' = 'Bundle.length' . 'stream''
is all the same as setting
'length' = 'basicLength'.
This prevents any stream fusion from happening.

This commit resolves this problem by resetting 'length' back
to be @'Bundle.length' . 'stream'@, and instead replacing
cyclic occurrence of 'length' with 'basicLength'
(Just *inlined the simplification result of the definition*).
Now 'length' is both inlinable and fusible, even with older GHCs.

Fixes: #306
See also: #97
  #111
  #155
lehins pushed a commit that referenced this issue Jan 16, 2021
This change makes fusible 'Data.Vector.Generic.length',
which currently can be inlined but doesn't fuse well.
Before this revision, 'length' uses non-fusible 'stream''.
This revision replaces 'stream'' with fusible 'stream',
and at the same time substitute the mutually-recursive
occurrences of 'length' with 'basicLength'.

Rationale:
The current definition was introduced in the commit
a811a86.
Prior to that commit,
'length' could not even be inlined with older GHCs,
which elected 'length' to be a loop-breaker due to the cyclic
references among 'clone', 'unsafeCopy', 'length' and 'stream':
* 'clone' refers to 'length' and 'unsafeCopy' in its definition;
* 'unsafeCopy' refers to 'length' in its definition;
* 'length' referred to 'stream' in its definition;
* 'stream' refers to none of the above in its definition,
  but the rule 'New.unstream/stream' rewrites
  @'New.unstream' ('stream' v)@ with @'clone' v@.
This failure of inlining was reported as
#97.

To be precise, this cycle of references is immaterial with newer
GHCs like GHC 8.8.3.
Since 'New.unstream' does not occur in the definitions of
'clone', 'unsafeCopy', and 'length',
indefinite inlining will not happen anyway.
GHC 8.8.3 seems to detect this immateriality of the
referencial loop in question and refrains from setting 'length' as a
loop-breaker, even with
acdcff3
(the parent commit of a811a86).
However with older GHCs, including GHC 8.0.2, regarded
the cyclic references fatal and marked 'length' as a loop-breaker.
Note that GHC 8.0.2 was current at the time a811a86 was introduced.

The commit a811a86 resolved this by replacing 'stream'
with 'stream'' in the definition of 'length'. The function
'stream' refers to 'clone' in its fusion rule, but 'stream''
doesn't possess any rule. This cut open the cycle of references
and made 'length' inlinable.

However, since 'stream'' doesn't possess any rule, defining
'length' = 'Bundle.length' . 'stream''
is all the same as setting
'length' = 'basicLength'.
This prevents any stream fusion from happening.

This commit resolves this problem by resetting 'length' back
to be @'Bundle.length' . 'stream'@, and instead replacing
cyclic occurrence of 'length' with 'basicLength'
(Just *inlined the simplification result of the definition*).
Now 'length' is both inlinable and fusible, even with older GHCs.

Fixes: #306
See also: #97
  #111
  #155
@lehins lehins mentioned this issue Jan 17, 2021
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants